基于GPR的大型项目编译耗时过长,寻求GPRBuild构建剖析方法
Hey there! Let’s break down how to profile your GPR build and speed up those incremental recompiles—you’ve already spotted some low-hanging fruit with multiple gprbuild calls and overused substitution files, so let’s dig into the deeper stuff.
To get concrete data on where your build is spending time, you’ve got a few solid options:
1.1 Leverage gprbuild’s Verbosity & Timing Output
Start with gprbuild’s built-in flags to get granular visibility into each step:
- Run
gprbuild -v 2>&1to capture all verbose output (including compiler calls and dependency checks). Pipe this to a log file with timestamps to track how long each file takes to compile:
This log will show you exactly which source files or linking steps are eating up the most time.gprbuild -v 2>&1 | awk '/Compiling|Linking/ {print strftime("%H:%M:%S"), $0}' > build_timings.log - Use
gprbuild -dto print the full dependency tree for your project. This helps spot unintended dependencies that might be triggering unnecessary recompiles.
1.2 System-Level Profiling for Deep Dives
If you need to look beyond just per-file timings, system tools can reveal bottlenecks in gprbuild itself or the compiler:
- On Linux, use
/usr/bin/time -v gprbuild <your-project>.gprto get detailed stats on CPU usage, memory, and I/O operations. This can tell you if your build is bottlenecked by disk I/O (slow reads/writes) or CPU. - For function-level profiling, use
perf:
This will show you which parts ofperf record -g gprbuild <your-project>.gpr perf reportgprbuildor the Ada compiler are consuming the most cycles—great for identifying inefficiencies in dependency resolution or build logic.
A 5-minute recompile for a single modified file is way too slow—here’s how to tighten this up:
2.1 Verify Dependency Tracking is Correct
First, make sure gprbuild is only rebuilding what’s necessary:
- Run
gprbuild -dand check the dependency chain for your modified file. If it’s showing dependencies on dozens of unrelated files, you might have:- Unnecessary
withclauses in your Ada code pulling in extra packages. - Generated files (like IDL/ASN.1 outputs) not properly marked as generated in your GPR project. Add
Generated_Source_Filesto your project file for these to ensuregprbuildtracks their dependencies correctly.
- Unnecessary
- Use
gprclean -nto preview which files would be cleaned (and thus recompiled) on the next build. If this list is way larger than expected, it’s a sign of broken dependency tracking.
2.2 Eliminate Unnecessary Rebuild Triggers
Sometimes builds slow down due to accidental timestamp changes or misconfigured project paths:
- Check if tools like backup utilities or auto-saving editors are modifying source files’ timestamps without actual code changes. Use
ls -lto compare timestamps before/after a "clean" build. - Ensure your GPR’s
Object_DirandExecutable_Dirare isolated to your project—sharing these with other projects can lead to cross-contamination and unexpected rebuilds.
2.3 Add Compiler Caching
For repetitive compile steps, a caching tool can cut down time drastically:
- Use
ccachewith your Ada compiler (e.g., GNAT). Set up a wrapper script forgnatgccthat usesccache, then update your GPR project to use this wrapper:
Then add# Create a wrapper script named gnatgcc_ccache #!/bin/bash exec ccache gnatgcc "$@"Compiler => "gnatgcc_ccache"to your GPR project’spackage Compilersection. This will cache compiled object files and reuse them when the source and compiler flags haven’t changed.
Before diving into deep profiling, these easy fixes can give you immediate gains:
- Enable parallel compilation with
gprbuild -j N, whereNis your CPU core count + 1 (e.g.,-j 8for a 7-core CPU). This splits the build across multiple threads and can halve total compile time. - Replace multiple separate
gprbuildcalls with an aggregate project. Aggregate projects let you build all subprojects in one go, sharing dependency caches and avoiding redundant setup steps. - Isolate generated code build steps: If you’re generating Ada code from IDL/ASN.1 files, run those generation steps only when the source definition files change, not on every build. Add a custom rule in your GPR project to trigger generation only when needed.
内容的提问来源于stack exchange,提问作者LambdaBeta

