Safeguard
Developer Tools•

How do you stop compiler build paths leaking into binaries?

Use the GCC and Clang prefix map flags to rewrite your build directory in debug info and file macros. See which flag covers what and where it falls short.

Safeguard Security Team
3 min read

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

FlagWhat it rewritesAvailable since
debug prefix mapDirectory prefixes in debug informationAll GCC versions, Clang 3.8
macro prefix mapPaths from the file macro, such as in assert callsGCC 8, Clang 10
file prefix mapAlias for both of the aboveGCC 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

  1. Put the flag in your common compiler flags, not in one project.
  2. Build in two different directories.
  3. Compare checksums. If they differ, run diffoscope and search the output for the directory name.
  4. Review any step that writes compile options into a file.
  5. 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.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.