Closed SkiFire13 closed 6 months ago
Assigning priority as discussed in the Zulip thread of the Prioritization Working Group.
@rustbot label -I-prioritize +P-medium
Moreover this shouldn't be needed in the first place since --remap-path-prefix promises to "remap source names in all output (compiler messages and output files)" (from the output of rustc --help -v), "including [...] debug information" (from the rustc book here).
Perhaps this should be amended to say compiler output but not linker outputs. PDB files are generated at the linking step, which is probably why https://github.com/rust-lang/rust/issues/88982 sees non-determinism for --crate-type=bin (linked) and not for --crate-type=rlib (not linked).
Passing /pdbaltpath:%_PDB%
to the linker to put a relative path to the PDB files is probably the best choice, as it is the least destructive, and the debugger will look for PDB files next to the executables, so it will be able to find it. Chromium uses this for its Windows linking step as well: https://source.chromium.org/chromium/chromium/src/+/main:build/config/compiler/BUILD.gn;drc=21dcb365c1eae5e99eb9ae6ef78bfe3c9372057e;l=2358
Doing this with --remap-path-prefix
could work if you can figure out which "to-be-remapped" path is going to be the path being written by the linker, and then pass the resulting path to /pdbaltpath
. I must confess I am not sure how linking is being done, but I assume the binary is being linked by a dedicated linker, not by rustc itself? If so that is not too reliable.
rustc could provide a switch to remove the absolute path to PDB files, which would just map to -Clink-arg=/pdbaltpath:%_PDB%
. The value proposition there seems low, since you can pass that as the user anyway.
Determinism is important for both release and debug builds, so I don't believe there is anything release-mode specific here or that a solution should be chosen that doesn't deal with debug mode?
but doing so will break backtraces with RUST_BACKTRACE='full'
Could you say what is breaking about backtraces with -Clink-arg=/pdbaltpath:%_PDB%
?
Could you say what is breaking about backtraces with
-Clink-arg=/pdbaltpath:%_PDB%
?
Without that flag I get something like:
```
thread 'main' panicked at 'foo', src\main.rs:2:5
stack backtrace:
0: 0x7ff6258483af - std::backtrace_rs::backtrace::dbghelp::trace
at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b\/library\std\src\..\..\backtrace\src\backtrace\dbghelp.rs:98
1: 0x7ff6258483af - std::backtrace_rs::backtrace::trace_unsynchronized
at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b\/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
2: 0x7ff6258483af - std::sys_common::backtrace::_print_fmt
at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b\/library\std\src\sys_common\backtrace.rs:67
3: 0x7ff6258483af - std::sys_common::backtrace::_print::impl$0::fmt
at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b\/library\std\src\sys_common\backtrace.rs:46
4: 0x7ff625855e7a - core::fmt::write
at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b\/library\core\src\fmt\mod.rs:1115
5: 0x7ff6258464d8 - std::io::Write::write_fmt
But with it it just prints:
```
thread 'main' panicked at 'foo', src\main.rs:2:5
stack backtrace:
0: 0x7ff689dd83af -
This seems to happen because the pdb file is searched relative to the current working directory, and when running cargo run
that's often not the directory with the executable and pdb files. -Clink-args=/pdbaltpath:target/release/%_PDB%
appears to work, but only as long as you execute it from the crate root, which is definitely not ideal.
Can cargo run
move to the crate root before executing the target executable? Then cargo could pass -Clink-args=/pdbaltpath:target/release/%_PDB%
(or debug) while other build systems pass -Clink-arg=/pdbaltpath:%_PDB%
or whatever works for them?
Wouldn't that break any workflow that relies on the current working directory always being where cargo run
is executed from?
Wouldn't that break any workflow that relies on the current working directory always being where cargo run is executed from?
I think this meant the crate root instead of the cwd? I had no idea that would be a common thing, but you're right. It would change any use of std::env::current_dir()
. I would expect std::env::current_exe()
to be more commonly used for relative paths, as it doesn't depend on running from a cargo source tree, but maybe I am wrong.
Regardless, I can see why changing run
behaviour isn't ideal. The MSVC linker doesn't present a whole lot of options though, as the path relative to where you plan to run the binary has to be encoded into the pdb files if you want a deterministic output.
It seems the options are:
cargo run
backtraces always work, debuggers work: PDB absolute paths. This is the default behaviour.cargo run
backtraces work from the exe's directory: -Clink-arg=/pdbaltpath:%_PDB%
cargo run
backtraces work from the crate root, but debuggers won't work: -Clink-args=/pdbaltpath:target/release/%_PDB%
Have I missed an option?
There's no option that I can see with both deterministic output and backtraces working from arbitrary working directories.
AIUI, this github issue is about --remap-path-prefix not adding a -Clink-args
flag, essentially. It would be nice if deterministic builds were easier to get! But based on all of the above, it seems to me that is better solved through Cargo than through rustc's --remap-path-prefix
, perhaps behind a Cargo flag in https://github.com/rust-lang/rfcs/pull/3127.
As a convenience, maybe cargo run
could provide an option to move to the exe's directory to run it, instead of users doing (cd target/release && cargo run)
, which would let option 2 be more ergonomic while also supporting debuggers.
Would it be possible to have cargo run
create a symbolic link to the pdb
file or the target
directory when it's not already present in the current working directory? This would partially solve the ergonomic problems of approaches 2 and 3
It'd probably be easier to have cargo run
set either _NT_SYMBOL_PATH
or _NT_ALTERNATE_SYMBOL_PATH
(_NT_ALT_SYMBOL_PATH
? they seem to spell it both ways), which effect the default search path for the windows APIs used for backtraces
Any update on this? :)
I've just opened https://github.com/rust-lang/rust/pull/121297 which solves the problem by making rustc
always pass /PDBALTPATH:%_PDB%
to the linker. This seems like the best solution to me. The PR is currently blocked on backtrace-rs not handling this properly, but I've opened https://github.com/rust-lang/backtrace-rs/pull/584, which will hopefully fix that.
Spawned off of https://github.com/rust-lang/rust/issues/87805#issuecomment-894202194
When passing
--remap-path-prefix C:\\path\\to\\project=nothing_to_see_here
to rustc I would expect all paths that start withC:\path\to\project
to be replaced withnothing_to_see_here
, instead aC:\path\to\project\target\release\deps\crate_name.pdb
is still present.Note that this happens even in release mode, because rustc always tells the msvc linker to generate
.pdb
files.This can be "fixed" by passing either
-Clink-arg=/PDBALTPATH:%_PDB%
,-Clink-arg=/DEBUG:NONE
or-Zstrip=debuginfo
to rustc, but doing so will break backtraces withRUST_BACKTRACE='full'
(RUST_BACKTRACE=1
already prints almost nothing in release mode). As a sidenote, do we really need backtraces in release mode, and by consequence.pdb
files? They will break anyway if only the.exe
is distributed or thetarget
directory is deleted.Moreover this shouldn't be needed in the first place since
--remap-path-prefix
promises to "remap source names in all output (compiler messages and output files)" (from the output ofrustc --help -v
), "including [...] debug information" (from the rustc book here). Also note that neitherrustc --help -v
nor the rustc book mention the need to pass one of those arguments to rustc to remap/remove the path to the.pdb
file, which makes it harder for non-experts to know how to remove them.rustc --version --verbose
: