Skip to content

feat(trim-paths): stabilize profile.trim-paths - #17488

Open
weihanglo wants to merge 2 commits into
rust-lang:masterfrom
weihanglo:trim-paths
Open

weihanglo wants to merge 2 commits into
rust-lang:masterfrom
weihanglo:trim-paths

Conversation

@weihanglo

@weihanglo weihanglo commented Sep 18, 2026

Copy link
Copy Markdown
Member

Stabilization report: profile.trim-paths

Resolves #12137
Resolves rust-lang/rust#111540
RFC: https://rust-lang.github.io/rfcs/3127-trim-paths.html

What is stabilized

The rustc side --remap-path-scope was already stabilized in Rust 1.95 via rust-lang/rust#147611

This stabilizes the Cargo side:

  • profile.<name>.trim-paths = "none" | "object" | "all"
    in both manifest and config
  • The remap rules of how Cargo passes --remap-path-{prefix,scope}.
    The exact remap prefixes still stay unspecified.
  • The unremap file <artifact>.trim-paths.json (schema v1),
    which is emitted beside final artifacts when debuginfo is on.
  • CARGO_TRIM_PATHS_SCOPE and CARGO_TRIM_PATHS_REMAP for build scripts.

When this is merged and sync in rust-lang/rust,
we'll also stabilize

  • The rust-gdb and rust-lldb unremap loaders.
    RUST_GDB_TRIM_PATHS=unstable and RUST_LLDB_TRIM_PATHS=unstable are not needed anymore.

See doc for details:

## Profile `trim-paths` option
* Tracking Issue: [rust-lang/cargo#12137](https://github.com/rust-lang/cargo/issues/12137)
* Tracking Rustc Issue: [rust-lang/rust#111540](https://github.com/rust-lang/rust/issues/111540)
This adds a new profile setting to control how paths are sanitized in the resulting binary.
This can be enabled like so:
```toml
cargo-features = ["trim-paths"]
[package]
# ...
[profile.release]
trim-paths = "object"
```
To set this in a profile in Cargo configuration,
you need to use either `-Z trim-paths` or `[unstable]` table to enable it.
For example,
```toml
# .cargo/config.toml
[unstable]
trim-paths = true
[profile.release]
trim-paths = "object"
```
### Documentation updates
#### trim-paths
*as a new ["Profiles settings" entry](./profiles.html#profile-settings)*
The `trim-paths` option controls the scope of path sanitization in build outputs
Paths are sanitized according to these [remapping rules].
The valid options are:
- `"none"` --- disables path sanitization.
- `"object"` --- sanitizes paths embedded in compiled executables and libraries.
Useful for improving artifact reproducibility
with less impact on local development.
- `"all"` --- sanitizes paths in all supported locations.
Useful for hermetic or remote builds that need artifacts and diagnostics
to be independent of the build environment.
> [!WARNING]
> The `"all"` option remaps compiler diagnostics,
> including [compiler JSON messages](./external-tools.md#json-messages).
> Some remapped paths may not resolve to files on the local filesystem,
> which can affect editors and other tools that consume the diagnostic output.
For details about each scope,
see rustc's [`--remap-path-scope`] documentation.
By default, `trim-paths` is not set and path sanitization is disabled for all profiles.
You can enable it by specifying this option in `Cargo.toml`:
```toml
[profile.dev]
trim-paths = "all"
[profile.release]
trim-paths = "object"
```
[`--remap-path-scope`]: ../../rustc/remap-source-paths.html#--remap-path-scope
[remapping rules]: #remapping-rules
##### Remapping rules
The exact remap path prefixes are unspecified and may change across Cargo versions.
Tools that map paths embedded in artifacts back to local sources
should consume [unremap files] instead of interpreting these prefixes.
[unremap files]: #unremap-files
If `trim-paths` is not `"none"`,
then the following paths are sanitized if they appear in a selected scope:
1. Path to the source files of the standard and core library (sysroot) will begin with `/rustc/<rustc commit hash>`,
e.g. `/home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs` ->
`/rustc/fe72845f7bb6a77b9e671e6a4f32fe714962cec4/library/core/src/result.rs`
2. Path to a local package within the workspace will begin with `.`,
which replaces the workspace root,
e.g. `/home/username/crate/src/lib.rs` -> `./src/lib.rs`.
This also covers path dependencies located inside the workspace directory.
3. Path to a registry dependency will begin with `/cargo/registry/<registry id>`,
which replaces the registry's extraction directory,
e.g. `/home/username/.cargo/registry/src/index.crates.io-6f17d22d3f0a95d1/foo-0.1.0/src/lib.rs` ->
`/cargo/registry/6f17d22d3f0a95d1/foo-0.1.0/src/lib.rs`.
4. Path to a git dependency will begin with `/cargo/git/<git source id>/<revision>`,
which replaces the checkout directory.
`<revision>` is a prefix of the resolved commit ID recorded in the lockfile.
5. Path to a path dependency outside the workspace will be replaced with
`/cargo/deps/<package name>-<package version>`.
6. Path into the build directory, for example `OUT_DIR` generated sources,
will begin with `/cargo/build-dir`.
`<registry id>` and `<git source id>` are opaque stable hashes of the dependency's source.
Vendored copies of registry or git dependencies
(via [source replacement](./source-replacement.md))
are sanitized by their file location instead,
like workspace paths when inside the workspace directory,
otherwise like path dependencies.
##### Unremap files
When the `object` scope is active and debuginfo is enabled,
Cargo writes an unremap file beside each final artifact.
The file is aimed at helping debuggers substitute sanitized paths back to local ones,
e.g., via GDB's `set substitute-path` or LLDB's `target.source-map`.
The Rust toolchain provides `rust-gdb` and `rust-lldb` wrappers,
which can load unremap files automatically.
This integration is currently unstable and available only in nightly toolchains.
To enable it,
set `RUST_GDB_TRIM_PATHS=unstable` or `RUST_LLDB_TRIM_PATHS=unstable` respectively.
The unremap file name ends with `.trim-paths.json`.
For example,
your `my-app` executable would come with an unremap file named
`my-app.trim-paths.json` beside it.
The unremap file is in JSON format:
* `v` carries the format version.
* `rust_version` and `workspace_root` are file-level metadata,
namely the toolchain version and the workspace root.
* `remaps` is an array of records.
Each record maps a sanitized path prefix in the artifact
(`from`) back to the local path it replaced (`to`),
ordered by the `from` prefix.
Note that this follows the debugger substitution direction,
which is the inverse of `--remap-path-prefix`.
An example of the unremap file:
```json
{
"v": 1,
"rust_version": "1.96.0-nightly",
"workspace_root": "/home/me/app",
"remaps": [
{ "from": ".", "to": "/home/me/app" },
{ "from": "/cargo/build-dir", "to": "/home/me/app/target" },
{ "from": "/cargo/registry/6f17d22d3f0a95d1", "to": "/home/me/.cargo/registry/src/index.crates.io-6f17d22d3f0a95d1" },
{ "from": "/rustc/abc123", "to": "/home/me/.rustup/toolchains/nightly/lib/rustlib/src/rust" }
]
}
```
Since it is meant to be a debugging aid,
it includes absolute paths of your system,
so there is no artifact privacy guarantee.
You might want to exclude `*.trim-paths.json` files when distributing artifacts.
##### Limitations
`trim-paths` supports remapping source path prefixes as a best effort.
Linkers may add paths that rustc cannot remap.
See [the limitations section][remap-limitation] on rustc's documentation for more.
For example, on macOS,
linkers generate OSO entries containing absolute paths to object files
when debuginfo is enabled.
The following profile settings keep these paths out of the executable
while preserving debuginfo in a separate dSYM bundle:
```toml
[profile.release]
debug = true
trim-paths = "object"
split-debuginfo = "packed"
strip = "debuginfo"
```
The dSYM bundle can be used for debugging,
but it still contains absolute paths.
[remap-limitation]: ../../rustc/remap-source-paths.html#caveats-and-limitations
#### Environment variable
*as a new entry of ["Environment variables Cargo sets for build scripts"](./environment-variables.md#environment-variables-cargo-sets-for-crates)*
* `CARGO_TRIM_PATHS_SCOPE` --- The value of `trim-paths` profile option.
If the build script introduces absolute paths to built artifacts (such as by invoking a compiler),
the user may request them to be sanitized in different types of artifacts.
Common paths requiring sanitization include `OUT_DIR`, `CARGO_MANIFEST_DIR` and `CARGO_MANIFEST_PATH`,
plus any other introduced by the build script, such as include directories.
> [!NOTE]
> For forward compatibility,
> build scripts should accept a comma-separated list of scopes.
* `CARGO_TRIM_PATHS_REMAP` --- The `<from>=<to>` path remap pairs Cargo passes to the compiler,
joined by the platform path separator.
Only set when `trim-paths` profile is active.
Build scripts can forward these mappings to C/C++ compilers and other tools,
for example via `cc`'s `-ffile-prefix-map`,
to sanitize paths consistently with the rest of the build.

What is not stabilized / included

  • This doesn't guarantee full sanitization. It is a best-effort feature.
  • Other --remap-path-scope values in rustc (macro, diagnostics, debuginfo, coverage),
    boolean values, and comma-separated list options.
    These are removed in fix(trim-paths)!: limit options to none|object|all #17432.
    They can come back later when needed.
  • A default trim-path value for built-in profiles.
    RFC originall proposed to set release to "object".
    This is left for future when this is more adopted and battle-tested.
    We have loose stability guarantee for changing profile settings anyway.
  • __CARGO_RUSTC_BOOTSTRAP_WS_REMAP.
    This stays as an internal thing between rustc bootstrap and cargo
    (see feat(trim-paths): honor workspace prefix override from env #17349, fix(trim-paths): custom workspace-relative member paths remap #17366)
  • Doctest remapping and documentation scope.
    This will be integrated in the future incrementally
    when those scopes and features are stable.
  • The exact remap prefixes are unspecified as documented.
    However, in practice,
    rustc bootstrap and debugger depend on the stabilized shape,
    so any change needs careful coordination with them.
  • Unremap files for artifact deps: deferred, non-blocking.
  • build-rs API for the two build script variables: deferred, non-blocking.
  • If there are new kinds of artifacts, we can decide whether to remap freely.

Doors closed

  • The trim-paths profile key name, its shape, and its options.
  • The unremap file name suffix .trim-paths.json and the v1 schema.
  • The environment variable CARGO_TRIM_PATHS_SCOPE and CARGO_TRIM_PATHS_REMAP.

Post-RFC changes

  • rustc removed split-debuginfo scopes,
    and Cargo followed and stopped caring split debuginfo.
  • The RFC remapped the current package to relative paths and every dependency to <name>-<version>.
    In fix(trim-paths): unambiguous and reversible remap rules #17302 we chose workspace members relative remap,
    so debuggers resolve workspace sources with zero configuration.
    The RFC worried that relative paths only work when running from the right directory,
    and symbolication tools need a second process for joining workspace relative paths.
    THe unremap file has workspace_root, so the join is fairly mechanical.
    Remap prefixes are unspecified anyway,
    so we can still change if it turns out not ideal.
  • The unremap file is new (introduced in feat(trim-paths): emit unremap files for final artifacts #17303),
    for helping debugging find sources,
    as well as our keeping remap rules unspecified.
    The RFC had no answer about this.
  • CARGO_TRIM_PATHS_REMAP build script env is new.
    It lets build scripts forward the same rules to C/C++ compilers to flags like -fmacro-prefix-map.
    cc-rs has integrated that since feat: inherit path remap rules from cargo trim-paths cc-rs#1794.

Feedback

Known limitations

This sanitization is best-effort. See

  • rustc: https://doc.rust-lang.org/rustc/remap-source-paths.html#caveats-and-limitations
  • Cargo:
    ##### Limitations
    `trim-paths` supports remapping source path prefixes as a best effort.
    Linkers may add paths that rustc cannot remap.
    See [the limitations section][remap-limitation] on rustc's documentation for more.
    For example, on macOS,
    linkers generate OSO entries containing absolute paths to object files
    when debuginfo is enabled.
    The following profile settings keep these paths out of the executable
    while preserving debuginfo in a separate dSYM bundle:
    ```toml
    [profile.release]
    debug = true
    trim-paths = "object"
    split-debuginfo = "packed"
    strip = "debuginfo"
    ```
    The dSYM bundle can be used for debugging,
    but it still contains absolute paths.
    [remap-limitation]: ../../rustc/remap-source-paths.html#caveats-and-limitations

Implementation

History

PR Merged Title
#12625 2023-10-31 implement RFC 3127 -Ztrim-paths
#12900 2023-10-31 set env CARGO_TRIM_PATHS for build scripts
#12908 2023-11-02 merge trim-paths from different profiles
#13118 2023-12-06 assert OSO and SO cannot be trimmed
#14389 2024-08-12 rustdoc supports trim-paths for diagnostics
#14908 2024-12-09 use Path::push to construct remap-path-prefix
#14917 2024-12-11 use stable hash from rustc-stable-hash
#15614 2025-06-02 remap all paths to build.build-dir
#15621 2025-06-02 enable more tests for windows-msvc
#16536 2026-01-21 --remap-path-scope stabilized in 1.95-nightly
#17104 2026-06-15 emit CARGO_TRIM_PATHS_REMAP for build.rs
#17221 2026-07-15 exercise GDB on windows-gnu
#17302 2026-08-03 unambiguous and reversible remap rules
#17303 2026-08-04 emit unremap files for final artifacts
#17326 2026-08-07 exercise unremap files with debuggers
#17338 2026-08-08 /cargo/deps fallback sources
#17337 2026-08-10 workspace remap under -Zroot-dir
#17349 2026-08-11 honor workspace prefix override from env
#17366 2026-08-26 custom workspace-relative member paths remap
#17424 2026-09-02 remove default scope from release profile
#17425 2026-09-02 docs: add limitations and polish
#17432 2026-09-04 limit options to none|object|all
#17476 2026-09-15 unremap file in one JSON doc

Test coverage

  • Remap for each dependency kind
  • "object" with every split-debuginfo mode
  • "all" diagnostics remapping for rustc and rustdoc
  • The new build-script environment variables.
  • Real world debugger exercises with GDB, LLDB, and CDB
  • unremap files with rebuilds, cargo clean, JSON messages
  • rustc bootstrap workspace prefix override
  • -Zbuild-std backtraces show /rustc/<hash> paths

Follow-ups after stabilization


🤖 LLM disclosure: impl history was generated. heading was generated. meats are human-written.

This stabilizes several parts:

* `profile.<name>.trim-paths = "none" | "object" | "all"`
  in both manifest and config
* The remap rules of how Cargo passes `--remap-path-{prefix,scope}`.
  The exact remap prefixes still stay unspecified.
* The unremap file `<artifact>.trim-paths.json` (schema v1),
  which is emitted beside final artifacts when debuginfo is on.
* `CARGO_TRIM_PATHS_SCOPE` and `CARGO_TRIM_PATHS_REMAP` for build scripts.

This is assumed to be stabilized in 1.101.
No drift. Just move to final locations.
@weihanglo weihanglo added relnotes Release-note worthy Z-trim-paths Nightly: path sanitization labels Sep 18, 2026
@rustbot rustbot added A-cfg-expr Area: Platform cfg expressions A-documenting-cargo-itself Area: Cargo's documentation A-manifest Area: Cargo.toml issues A-profiles Area: profiles A-unstable Area: nightly unstable support Command-clean labels Sep 18, 2026
@weihanglo weihanglo removed the A-cfg-expr Area: Platform cfg expressions label Sep 18, 2026
Comment thread src/workspace/features.rs

/// Allow setting trim-paths in a profile to control the sanitisation of file paths in build outputs.
(unstable, trim_paths, "", "reference/unstable.html#profile-trim-paths-option"),
(stable, trim_paths, "1.101", "reference/profiles.html#trim-paths"),

@weihanglo weihanglo Sep 18, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aimed at Rust 1.101

View changes since the review

@weihanglo
weihanglo marked this pull request as ready for review September 18, 2026 22:44
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 18, 2026
@rustbot

rustbot commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

r? @Muscraft

rustbot has assigned @Muscraft.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @Muscraft, @epage, @weihanglo
  • @Muscraft, @epage, @weihanglo expanded to Muscraft, epage, weihanglo
  • Random selection from Muscraft, epage

@weihanglo weihanglo added the T-cargo Team: Cargo label Sep 18, 2026
@weihanglo

weihanglo commented Sep 18, 2026

Copy link
Copy Markdown
Member Author

While this is still calling for testing. I think it is fine FCP in parallel. Please read the PR description for the stabilization report.

@rfcbot fcp merge

also cc @Urgau

@rust-rfcbot

This comment was marked as duplicate.

@weihanglo

This comment was marked as duplicate.

@rust-rfcbot

rust-rfcbot commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

@weihanglo has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rust-rfcbot rust-rfcbot added proposed-final-comment-period An FCP proposal has started, but not yet signed off. disposition-merge FCP with intent to merge labels Sep 18, 2026

@epage epage left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good.

View changes since this review


## Default profiles

### dev

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to update dev and release?

[`build.rustflags`]. Note that since Rust 1.55, `RUSTFLAGS` is removed from
the environment; scripts should use `CARGO_ENCODED_RUSTFLAGS` instead.
* `CARGO_PKG_<var>` --- The package information variables, with the same names and values as are [provided during crate building][variables set for crates].
* `CARGO_TRIM_PATHS_SCOPE` --- The value of the [`trim-paths`] profile option.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not including build-rs on or before stabilization is poor messaging. Including it would also provide an example for those not using it in how to read things.

@rustbot rustbot added S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-documenting-cargo-itself Area: Cargo's documentation A-manifest Area: Cargo.toml issues A-profiles Area: profiles A-unstable Area: nightly unstable support Command-clean disposition-merge FCP with intent to merge proposed-final-comment-period An FCP proposal has started, but not yet signed off. relnotes Release-note worthy S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. T-cargo Team: Cargo Z-trim-paths Nightly: path sanitization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking Issue for trim-paths RFC 3127 Tracking Issue for trim-paths RFC 3127

5 participants