Skip to content

Commit 5ca823a

Browse files
authored
fix(trim-paths): unambiguous and reversible remap rules (#17302)
### What does this PR try to resolve? Part of <#12137>. This was discussed during 2026 all-hands rust-lang/all-hands-2026#38 (comment) Every remap rule now substitutes a distinct prefix instead of stripping the source prefix to an empty string. This makes the source remap more unambiguous and reversible. | Category | From | To | |---------------------|----------------------------------------------|------------------------------------| | Sysroot | `<sysroot>/lib/rustlib/src/rust` | `/rustc/<commit-hash>` | | Registry dep | `~/cargo/registry/src/<registry-dir>` | `/cargo/registry/<registry-id>` | | Git dep | `~/cargo/git/checkouts/<repo-dir>/<rev-dir>` | `/cargo/git/<git-source-id>/<rev>` | | Workspace | `<workspace-root>` | `.` (workspace-relative) | | Path dep outside ws | `<pkg-root>` | `/cargo/path/<name>-<version>` | | Vendored | `<pkg-root>` (by file location) | workspace or path rules above | | Build directory | `<build-dir>` | `/cargo/build-dir` | ### How to test and review this PR? Commit by commit. * Old tests show the remap behavior changes. * New tests verify vendored dependencies are covered. * Docs are updated.
2 parents 614ec56 + 2a8b6fd commit 5ca823a

5 files changed

Lines changed: 457 additions & 171 deletions

File tree

doc/book/src/reference/unstable.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,11 +1549,32 @@ But the paths to these separate files are sanitized.
15491549

15501550
If `trim-paths` is not `none` or `false`, then the following paths are sanitized if they appear in a selected scope:
15511551

1552-
1. Path to the source files of the standard and core library (sysroot) will begin with `/rustc/[rustc commit hash]`,
1552+
1. Path to the source files of the standard and core library (sysroot) will begin with `/rustc/<rustc commit hash>`,
15531553
e.g. `/home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs` ->
15541554
`/rustc/fe72845f7bb6a77b9e671e6a4f32fe714962cec4/library/core/src/result.rs`
1555-
2. Path to the current package will be stripped, relatively to the current workspace root, e.g. `/home/username/crate/src/lib.rs` -> `src/lib.rs`.
1556-
3. Path to dependency packages will be replaced with `[package name]-[version]`. E.g. `/home/username/deps/foo/src/lib.rs` -> `foo-0.1.0/src/lib.rs`
1555+
2. Path to the current package will be stripped,
1556+
relatively to the current workspace root,
1557+
e.g. `/home/username/crate/src/lib.rs` -> `src/lib.rs`.
1558+
This also covers path dependencies located inside the workspace directory.
1559+
3. Path to a registry dependency will begin with `/cargo/registry/<registry id>`,
1560+
which replaces the registry's extraction directory,
1561+
e.g. `/home/username/.cargo/registry/src/index.crates.io-6f17d22d3f0a95d1/foo-0.1.0/src/lib.rs` ->
1562+
`/cargo/registry/6f17d22d3f0a95d1/foo-0.1.0/src/lib.rs`.
1563+
4. Path to a git dependency will begin with `/cargo/git/<git source id>/<revision>`,
1564+
which replaces the checkout directory.
1565+
`<revision>` is a prefix of the resolved commit ID recorded in the lockfile.
1566+
5. Path to a path dependency outside the workspace will be replaced with
1567+
`/cargo/path/<package name>-<package version>`.
1568+
6. Path into the build directory, for example `OUT_DIR` generated sources,
1569+
will begin with `/cargo/build-dir`.
1570+
1571+
`<registry id>` and `<git source id>` are opaque stable hashes of the dependency's source.
1572+
1573+
Vendored copies of registry or git dependencies
1574+
(via [source replacement](./source-replacement.md))
1575+
are sanitized by their file location instead,
1576+
like workspace paths when inside the workspace directory,
1577+
otherwise like path dependencies.
15571578

15581579
When a path to the source files of the standard and core library is *not* in scope for sanitization,
15591580
the emitted path will depend on if `rust-src` component is present.

src/compiler/custom_build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResul
403403
if let Some(trim_paths) = unit.profile.trim_paths.as_ref() {
404404
cmd.env("CARGO_TRIM_PATHS_SCOPE", trim_paths.to_string());
405405
if !trim_paths.is_none() {
406-
let pairs = super::trim_paths_remap(build_runner, unit);
406+
let pairs = super::trim_paths::trim_paths_remap(build_runner, unit);
407407
cmd.env(
408408
"CARGO_TRIM_PATHS_REMAP",
409409
paths::join_paths(&pairs, "CARGO_TRIM_PATHS_REMAP")?,

src/compiler/mod.rs

Lines changed: 3 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ mod output_sbom;
4848
pub mod rustdoc;
4949
pub mod standard_lib;
5050
pub mod timings;
51+
mod trim_paths;
5152
mod unit;
5253
pub mod unit_dependencies;
5354
pub mod unit_graph;
@@ -95,6 +96,8 @@ pub(crate) use self::layout::Layout;
9596
pub use self::lto::Lto;
9697
use self::output_depinfo::output_depinfo;
9798
use self::output_sbom::build_sbom;
99+
use self::trim_paths::trim_paths_args;
100+
use self::trim_paths::trim_paths_args_rustdoc;
98101
use self::unit_graph::UnitDep;
99102

100103
use crate::compiler::future_incompat::FutureIncompatReport;
@@ -115,8 +118,6 @@ use crate::workspace::{Feature, PackageId, Target};
115118

116119
use cargo_util::{ProcessBuilder, ProcessError, paths};
117120
use cargo_util_schemas::manifest::TomlDebugInfo;
118-
use cargo_util_schemas::manifest::TomlTrimPaths;
119-
use cargo_util_schemas::manifest::TomlTrimPathsValue;
120121
use cargo_util_terminal::Verbosity;
121122
use rustfix::diagnostics::Applicability;
122123

@@ -1525,159 +1526,6 @@ fn features_args(unit: &Unit) -> Vec<OsString> {
15251526
args
15261527
}
15271528

1528-
/// Like [`trim_paths_args`] but for rustdoc invocations.
1529-
fn trim_paths_args_rustdoc(
1530-
cmd: &mut ProcessBuilder,
1531-
build_runner: &BuildRunner<'_, '_>,
1532-
unit: &Unit,
1533-
trim_paths: &TomlTrimPaths,
1534-
) -> CargoResult<()> {
1535-
match trim_paths {
1536-
// rustdoc supports diagnostics trimming only.
1537-
TomlTrimPaths::Values(values) if !values.contains(&TomlTrimPathsValue::Diagnostics) => {
1538-
return Ok(());
1539-
}
1540-
_ => {}
1541-
}
1542-
1543-
for pair in trim_paths_remap(build_runner, unit) {
1544-
let mut arg = OsString::from("--remap-path-prefix=");
1545-
arg.push(pair);
1546-
cmd.arg(arg);
1547-
}
1548-
1549-
Ok(())
1550-
}
1551-
1552-
/// Generates the `--remap-path-scope` and `--remap-path-prefix` for [RFC 3127].
1553-
/// See also unstable feature [`-Ztrim-paths`].
1554-
///
1555-
/// [RFC 3127]: https://rust-lang.github.io/rfcs/3127-trim-paths.html
1556-
/// [`-Ztrim-paths`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-trim-paths-option
1557-
fn trim_paths_args(
1558-
cmd: &mut ProcessBuilder,
1559-
build_runner: &BuildRunner<'_, '_>,
1560-
unit: &Unit,
1561-
trim_paths: &TomlTrimPaths,
1562-
) -> CargoResult<()> {
1563-
if trim_paths.is_none() {
1564-
return Ok(());
1565-
}
1566-
1567-
// feature gate was checked during manifest/config parsing.
1568-
cmd.arg(format!("--remap-path-scope={trim_paths}"));
1569-
1570-
for pair in trim_paths_remap(build_runner, unit) {
1571-
let mut arg = OsString::from("--remap-path-prefix=");
1572-
arg.push(pair);
1573-
cmd.arg(arg);
1574-
}
1575-
1576-
Ok(())
1577-
}
1578-
1579-
/// Computes the `<from>=<to>` path remap pairs for [RFC 3127] trim-paths.
1580-
///
1581-
/// Order of `--remap-path-prefix` flags is important for `-Zbuild-std`.
1582-
/// We want to show `/rustc/<hash>/library/std` instead of `std-0.0.0`.
1583-
///
1584-
/// [RFC 3127]: https://rust-lang.github.io/rfcs/3127-trim-paths.html
1585-
pub(crate) fn trim_paths_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> [OsString; 3] {
1586-
[
1587-
package_remap(build_runner, unit),
1588-
build_dir_remap(build_runner),
1589-
sysroot_remap(build_runner, unit),
1590-
]
1591-
}
1592-
1593-
/// Path prefix remap rules for sysroot.
1594-
///
1595-
/// This remap logic aligns with rustc:
1596-
/// <https://github.com/rust-lang/rust/blob/c2ef3516/src/bootstrap/src/lib.rs#L1113-L1116>
1597-
fn sysroot_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString {
1598-
let mut remap = OsString::new();
1599-
remap.push({
1600-
// See also `detect_sysroot_src_path()`.
1601-
let mut sysroot = build_runner.bcx.target_data.info(unit.kind).sysroot.clone();
1602-
sysroot.push("lib");
1603-
sysroot.push("rustlib");
1604-
sysroot.push("src");
1605-
sysroot.push("rust");
1606-
sysroot
1607-
});
1608-
remap.push("=");
1609-
remap.push("/rustc/");
1610-
if let Some(commit_hash) = build_runner.bcx.rustc().commit_hash.as_ref() {
1611-
remap.push(commit_hash);
1612-
} else {
1613-
remap.push(build_runner.bcx.rustc().version.to_string());
1614-
}
1615-
remap
1616-
}
1617-
1618-
/// Path prefix remap rules for dependencies.
1619-
///
1620-
/// * Git dependencies: remove `~/.cargo/git/checkouts` prefix.
1621-
/// * Registry dependencies: remove `~/.cargo/registry/src` prefix.
1622-
/// * Others (e.g. path dependencies):
1623-
/// * relative paths to workspace root if inside the workspace directory.
1624-
/// * otherwise remapped to `<pkg>-<version>`.
1625-
fn package_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString {
1626-
let pkg_root = unit.pkg.root();
1627-
let ws_root = build_runner.bcx.ws.root();
1628-
let mut remap = OsString::new();
1629-
let source_id = unit.pkg.package_id().source_id();
1630-
if source_id.is_git() {
1631-
remap.push(
1632-
build_runner
1633-
.bcx
1634-
.gctx
1635-
.git_checkouts_path()
1636-
.as_path_unlocked(),
1637-
);
1638-
remap.push("=");
1639-
} else if source_id.is_registry() {
1640-
remap.push(
1641-
build_runner
1642-
.bcx
1643-
.gctx
1644-
.registry_source_path()
1645-
.as_path_unlocked(),
1646-
);
1647-
remap.push("=");
1648-
} else if pkg_root.strip_prefix(ws_root).is_ok() {
1649-
remap.push(ws_root);
1650-
remap.push("=."); // remap to relative rustc work dir explicitly
1651-
} else {
1652-
remap.push(pkg_root);
1653-
remap.push("=");
1654-
remap.push(unit.pkg.name());
1655-
remap.push("-");
1656-
remap.push(unit.pkg.version().to_string());
1657-
}
1658-
remap
1659-
}
1660-
1661-
/// Remap all paths pointing to `build.build-dir`,
1662-
/// i.e., `[BUILD_DIR]/debug/deps/foo-[HASH].dwo` would be remapped to
1663-
/// `/cargo/build-dir/debug/deps/foo-[HASH].dwo`
1664-
/// (note the `/cargo/build-dir` prefix).
1665-
///
1666-
/// This covers scenarios like:
1667-
///
1668-
/// * Build script generated code. For example, a build script may call `file!`
1669-
/// macros, and the associated crate uses [`include!`] to include the expanded
1670-
/// [`file!`] macro in-place via the `OUT_DIR` environment.
1671-
/// * On Linux, `DW_AT_GNU_dwo_name` that contains paths to split debuginfo
1672-
/// files (dwp and dwo).
1673-
fn build_dir_remap(build_runner: &BuildRunner<'_, '_>) -> OsString {
1674-
let build_dir = build_runner.bcx.ws.build_dir();
1675-
let mut remap = OsString::new();
1676-
remap.push(build_dir.as_path_unlocked());
1677-
remap.push("=/cargo/build-dir");
1678-
remap
1679-
}
1680-
16811529
/// Generates the `--check-cfg` arguments for the `unit`.
16821530
fn check_cfg_args(unit: &Unit) -> Vec<OsString> {
16831531
// The routine below generates the --check-cfg arguments. Our goals here are to

0 commit comments

Comments
 (0)