Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ jobs:
shell: pwsh
run: Add-Content $env:GITHUB_PATH "C:\Program Files (x86)\Windows Kits\10\Debuggers\arm64"
if: matrix.os == 'windows-11-arm'
- name: Check Windows MSVC debugger tool
run: cdb -version
if: matrix.rust == 'nightly-msvc'
- name: Check Windows GNU object tool
run: objdump --version
if: matrix.os == 'windows-latest' && matrix.rust == 'nightly-gnu'
- name: Check Windows GNU debugger tool
run: gdb --version
if: matrix.os == 'windows-latest' && matrix.rust == 'nightly-gnu'
Comment on lines +216 to +224

@weihanglo weihanglo Jul 15, 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.

I don't like these. However, we don't have a more fancier way yet to enforce tool availability in CI. Currently in #[cargo_test], requires runs during macro expansion time. If we enforce that tool's availability, jobs like clippy would also require those tools to be available.

We may want to add some feature to cargo-test-macro to skip when not running test, or we just make those tools/env globally set for the entire workflow.

I don't like either of them though

View changes since the review

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.

I do appreciate for debugging purposes the ability to see related tool versions

- name: Configure extra test environment
run: echo CARGO_CONTAINER_TESTS=1 >> $GITHUB_ENV
if: matrix.os == 'ubuntu-latest'
Expand Down
143 changes: 127 additions & 16 deletions tests/testsuite/profile_trim_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,8 +610,40 @@ mod object_works {
}
}

#[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))]
mod object_works {
use super::*;

fn inspect_debuginfo(path: &std::path::Path) -> Vec<u8> {
let parent = path.parent().expect("binary has a parent directory");
let file_name = path.file_name().expect("binary has a file name");
let output = std::process::Command::new("objdump")
// Avoid echoing the absolute input path in objdump's file header.
.current_dir(parent)
.arg("--dwarf=info")
.arg(file_name)
.output()
.expect("objdump works");
assert!(
output.status.success(),
"objdump failed with {}\nstdout:\n{}\nstderr:\n{}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
output.stdout
}

// rustc currently supports only split-debuginfo=off on windows-gnu.
// <https://github.com/rust-lang/rust/blob/47101adcea71daee3c2879218f5b883bcdf180aa/compiler/rustc_target/src/spec/base/windows_gnu.rs#L105-L107>
#[cargo_test(requires = "objdump")]
fn with_split_debuginfo_off() {
object_works_helper("off", inspect_debuginfo);
}
}

fn object_works_helper(split_debuginfo: &str, run: impl Fn(&std::path::Path) -> Vec<u8>) {
let registry_src = paths::home().join(".cargo/registry/src");
let registry_src = paths::home().join(".cargo").join("registry").join("src");

@epage epage Jul 15, 2026

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.

side note: I thought windows was also supposed to work with / but I've also observed this problem

View changes since the review

let registry_src_bytes = registry_src.as_os_str().as_encoded_bytes();
let rust_src = "/lib/rustc/src/rust".as_bytes();

Expand Down Expand Up @@ -644,23 +676,27 @@ fn object_works_helper(split_debuginfo: &str, run: impl Fn(&std::path::Path) ->
let pkg_root = p.root();
let pkg_root = pkg_root.as_os_str().as_encoded_bytes();

// Our baseline of which source roots are discoverable without object trimming.
p.cargo("build").run();

let bin_path = p.bin("foo");
assert!(bin_path.is_file());
let stdout = run(&bin_path);
// On windows-msvc every debuginfo is in pdb file, so can't find anything here.

// TODO: re-enable this check when rustc bootstrap disables remapping
// <https://github.com/rust-lang/cargo/pull/12625#discussion_r1371714791>
// assert!(memchr::memmem::find(&stdout, rust_src).is_some());

// `file!()` in `bar()` keeps untrimmed registry source in the executable
// even when debuginfo is separate.
assert!(memchr::memmem::find(&stdout, registry_src_bytes).is_some());

// The local package root occurs only in debuginfo in this fixture.
// MSVC puts that debuginfo in the PDB,
// while the other inspectors read embedded debuginfo.
if cfg!(target_env = "msvc") {
// TODO: re-enable this check when rustc bootstrap disables remapping
// <https://github.com/rust-lang/cargo/pull/12625#discussion_r1371714791>
// assert!(memchr::memmem::find(&stdout, rust_src).is_some());
assert!(memchr::memmem::find(&stdout, registry_src_bytes).is_none());
assert!(memchr::memmem::find(&stdout, pkg_root).is_none());
} else {
// TODO: re-enable this check when rustc bootstrap disables remapping
// <https://github.com/rust-lang/cargo/pull/12625#discussion_r1371714791>
// assert!(memchr::memmem::find(&stdout, rust_src).is_some());
assert!(memchr::memmem::find(&stdout, registry_src_bytes).is_some());
assert!(memchr::memmem::find(&stdout, pkg_root).is_some());
}
p.cargo("clean").run();
Expand Down Expand Up @@ -689,11 +725,17 @@ fn object_works_helper(split_debuginfo: &str, run: impl Fn(&std::path::Path) ->
let bin_path = p.bin("foo");
assert!(bin_path.is_file());
let stdout = run(&bin_path);

// Original sysroot source root should be trimmed.
assert!(memchr::memmem::find(&stdout, rust_src).is_none());

// Check line by line so macOS can exempt untrimmable `OSO` symbols.
for line in stdout.split(|c| c == &b'\n') {
let registry = memchr::memmem::find(line, registry_src_bytes).is_none();
let local = memchr::memmem::find(line, pkg_root).is_none();
if registry && local {
// original registry source root was trimmed.
let registry_is_trimmed = memchr::memmem::find(line, registry_src_bytes).is_none();
// original project root was trimmed.
let local_is_trimmed = memchr::memmem::find(line, pkg_root).is_none();
if registry_is_trimmed && local_is_trimmed {
continue;
}

Expand Down Expand Up @@ -877,8 +919,77 @@ Hello, Ferris!
);
}

// This test is disabled, as it currently doesn't work.
#[cfg(any())]
#[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))]
#[cargo_test(requires = "gdb")]
fn gdb_works_after_trimmed() {
use cargo_test_support::compare::assert_e2e;

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
edition = "2015"

[profile.dev]
trim-paths = "object"
"#,
)
.file(
"src/main.rs",
r#"
fn main() {
let msg = "Hello, Ferris!";
println!("{msg}");
}
"#,
)
.build();

p.cargo("build --verbose -Ztrim-paths")
.masquerade_as_nightly_cargo(&["-Ztrim-paths"])
.with_stderr_data(str![[r#"
[COMPILING] foo v0.0.0 ([ROOT]/foo)
[RUNNING] `rustc [..]--remap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s

"#]])
.run();

let bin_path = p.bin("foo");
assert!(bin_path.is_file());

// GitHub's Windows runner uses MinGW-builds GDB wrapper,
// which loses the boundary of spaced `-ex` args when forwarding them to `gdborig.exe`.
// Therefore we use a command file instead here.
//
// See <https://github.com/niXman/mingw-builds/blob/1d6a1c28/sources/gdb-wrapper/gdb-wrapper.c#L141-L145>
p.change_file(
"gdb.commands",
"break -source src/main.rs -line 4\nrun\nlist\ncontinue\n",
);
let stdout = String::from_utf8(
p.process("gdb")
.args(&["--batch", "--nx", "--quiet", "--command=gdb.commands"])
.arg(bin_path.strip_prefix(p.root()).unwrap())
.run()
.stdout,
)
.unwrap();
assert_e2e().eq(
&stdout,
str![[r#"
...
[..]Breakpoint 1,[..]
...
Hello, Ferris!
...

"#]],
);
}

#[cfg(target_env = "msvc")]
#[cargo_test(
requires = "cdb",
Expand All @@ -890,7 +1001,7 @@ fn cdb_works_after_trimmed() {

let run_debugger = |path| {
std::process::Command::new("cdb")
.args(["-c", "bp `main.rs:4`;g;g;q"])
.args(["-lines", "-c", r"bp `src\main.rs:3`;g;g;q"])
.arg(path)
.output()
.expect("debugger works")
Expand Down