buildRustCrate: remap crate source root to /<crateName>-<version>

buildRustCrate passes `--remap-path-prefix=$NIX_BUILD_TOP=/` so the
sandbox build directory is not embedded in compiled artifacts. The
resulting source path is `/$sourceRoot/src/...` — which works out to
`/<crateName>-<version>/src/...` only because fetchCrate happens to
unpack to a directory named after the crate.

When `src` is supplied directly — `lib.fileset.toSource` (always
`source`), `lib.cleanSource ./.`, a flake's `self`, or any
`<hash>-source` store path — stdenv unpacks to `$NIX_BUILD_TOP/source/`,
so every such crate ends up with `/source/src/lib.rs`. The crate
identity is gone from panic backtraces, `file!()` expansions, debuginfo,
and llvm-cov coverage maps. Workspace builds via crate2nix that source
each member with a fileset see all members collapse to the same prefix,
making per-crate coverage and backtrace attribution impossible without a
per-crate remap override.

Add a second, more specific remap of `$NIX_BUILD_TOP/$sourceRoot` to
`/<crateName>-<version>`. rustc applies `--remap-path-prefix` flags
last-match-wins, so this prefix wins for everything under the source
root — which in a buildRustCrate build is effectively everything that
would otherwise embed a sandbox path, including `OUT_DIR` (placed at
`$sourceRoot/target/build/` by configure-crate.nix). The broader
`$NIX_BUILD_TOP=/` remap stays as a fallback for any path outside
`$sourceRoot`.

This is safe with respect to the original remap's purpose:

- Reproducibility: still maps the per-build sandbox path to a fixed,
  build-independent string. `crateName` and `version` are already
  derivation inputs, so the result is deterministic.
- Closure size: still no store paths in the embedded strings.
- fetchCrate sources: `$sourceRoot` is `<crateName>-<version>` there,
  so the new remap rewrites `/<crateName>-<version>` to itself — the
  output is byte-for-byte identical. Only custom-`src` crates change,
  and they change from a degenerate `/source/...` to the same shape
  fetchCrate crates already had.
- The remap only affects path *strings* embedded in output (DWARF
  `DW_AT_comp_dir`/`DW_AT_name`, `file!()`, `Location::file()`, LLVM
  coverage filename tables). It does not change which files are read
  or compiled.

Users who depend on the old `/source/...` prefix can restore it via
`extraRustcOpts`, which is appended after these flags and therefore
wins under last-match-wins.
This commit is contained in:
Bernardo Meurer
2026-05-19 10:21:59 -04:00
parent 8cd8ee769a
commit a53ede53dc
2 changed files with 16 additions and 0 deletions
@@ -9,6 +9,7 @@
{
crateName,
version,
dependencies,
crateFeatures,
crateRenames,
@@ -32,6 +33,20 @@ let
(if release then "-C opt-level=3" else "-C debuginfo=2")
"-C codegen-units=${toString codegenUnits}"
"--remap-path-prefix=$NIX_BUILD_TOP=/"
# Map the unpacked source root to a stable, crate-identifying path.
# Sources from fetchCrate unpack to $NIX_BUILD_TOP/<crateName>-<version>,
# so the prefix above already yields /<crateName>-<version>/src/... and
# this remap is a no-op for them. Sources supplied via a custom `src`
# (lib.fileset.toSource, lib.cleanSource, a flake's `self`) all unpack to
# a fixed basename like `source`, so without this every such crate
# collapses to /source/src/... — losing crate identity in panic
# backtraces, file!() expansions, debuginfo, and coverage maps. rustc
# applies remaps last-match-wins, so this more-specific prefix wins
# for everything under the source root (including OUT_DIR, which
# configure-crate.nix places at $sourceRoot/target/build/); the
# broader $NIX_BUILD_TOP remap above remains as a fallback for any
# path that happens to fall outside $sourceRoot.
"--remap-path-prefix=$NIX_BUILD_TOP/$sourceRoot=/${crateName}-${version}"
# When the rust-src component is present (common with rust-overlay
# toolchains), rustc unvirtualises libstd source paths. Panic
# locations from monomorphised generic std code then embed the
@@ -543,6 +543,7 @@ lib.makeOverridable
buildPhase = buildCrate {
inherit
crateName
version
dependencies
crateFeatures
crateRenames