Use the prefix map flags. The file prefix map option rewrites your build directory in both debug information and the file macro, so two builds in different directories can produce the same binary. It exists in GCC 8 and Clang 10 or later. Older compilers need the debug prefix map option.
Why paths end up in binaries
Most compilers write the path of the source file into debug information so a debugger can find the source. Some also expand the file macro into the path, which is how paths appear in assertion messages. If your CI checks out code to a different directory on each job, every build embeds a different string.
The Reproducible Builds documentation says that, in most cases, post processing is needed to remove or normalise build paths, and for debug symbols there is no good post processing tool. Compiler flags that rewrite the path are the practical answer.
The three flags
| Flag | What it rewrites | Available since |
|---|---|---|
| debug prefix map | Directory prefixes in debug information | All GCC versions, Clang 3.8 |
| macro prefix map | Paths from the file macro, such as in assert calls | GCC 8, Clang 10 |
| file prefix map | Alias for both of the above | GCC 8, Clang 10 |
Each takes OLD=NEW. A sensible mapping sends your build directory to a fixed name:
cc -ffile-prefix-map=$(pwd)=. -c main.c
On Debian, packages using dpkg 1.19.1 or later, first shipped with Buster, can enable this through the fixfilepath build flag in debian/rules.
Where this falls short
Two limits from the same documentation are worth knowing.
First, some packages save their compile options in the build output. If options contain paths, the output still varies. This also applies to intermediate source files that other tools generate, which typically have random file names, so a fixed build path alone does not help in those cases.
Second, a tool that rewrites bytes after the fact can leave traces. The docs note that debugedit replaces the build path with a predefined one by rewriting bytes in place. Because it does not reorder the hash table of strings, the resulting bytes still depend on the original build path.
The documentation also mentions a build path prefix map specification in discussion with GCC developers, marked work in progress.
A practical routine
- Put the flag in your common compiler flags, not in one project.
- Build in two different directories.
- Compare checksums. If they differ, run diffoscope and search the output for the directory name.
- Review any step that writes compile options into a file.
- Repeat for the linker and for any code generators.
If you build in a container, you can also fix the checkout path, for example always build in the same directory. The documentation notes this works as a workaround but makes it harder to assess reproducibility with tools that vary the path on purpose.
Quick check
Do I need both the debug and macro flags?
The file prefix map flag is an alias for both, on GCC 8, Clang 10 and later.
Is a fixed build directory enough?
It works as a workaround, but prefix maps let the build run anywhere and still match.
Safeguard's SBOM and dependency scanning, generally available, inventories the libraries a C or C++ project depends on. The free scan at gold.safeguard.sh/scan can try it on a repository.
Sources
Last reviewed: 19 October 2026.