about summary refs log tree commit diff
diff options
context:
space:
mode:
authordanakj <danakj@chromium.org>2023-06-14 10:44:00 -0400
committerdanakj <danakj@chromium.org>2023-06-14 10:44:00 -0400
commit7e07271eaf6f8ae1f3b2c3ffeb46bf1c13f36bc1 (patch)
tree6aa89ec65c8af647d20eee773f8310b5e4ddf92b
parent5683791ebb7bbc440366635c322ad82badc554ca (diff)
downloadrust-7e07271eaf6f8ae1f3b2c3ffeb46bf1c13f36bc1.tar.gz
rust-7e07271eaf6f8ae1f3b2c3ffeb46bf1c13f36bc1.zip
Avoid absolute sysroot paths in the MSVC linker command line
When the `--sysroot` is specified as relative to the current working
directory, the sysroot's rlibs should also be specified as relative
paths. Otherwise, the current working directory ends up in the
absolute paths, and in the linker command line. And the entire linker
command line appears in the PDB file generated by the MSVC linker.

When adding an rlib to the linker command line, if the rlib's canonical
path is in the sysroot's canonical path, then use the current sysroot
path + filename instead of the full absolute path to the rlib. This
means that when `--sysroot=foo` is specified, the linker command line
will contain `foo/rustlib/target/lib/lib*.rlib` instead of the full
absolute path to the same.

This addresses https://github.com/rust-lang/rust/issues/112586
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs29
1 files changed, 27 insertions, 2 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8d346c8c0d0..9c53e5c0531 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorGuaranteed, Handler};
-use rustc_fs_util::fix_windows_verbatim_for_gcc;
+use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
 use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
@@ -2682,6 +2682,31 @@ fn add_upstream_native_libraries(
     }
 }
 
+// Rehome sysroot lib paths to be relative to the sysroot, which may be a relative
+// path specified by the user. If the sysroot is a relative path, and the sysroot rlibs
+// are specified as an absolute path, the linker command line can be non-deterministic
+// due to the paths including the current working directory. The linker command line
+// needs to be deterministic since it appears inside the PDB file generated by the MSVC
+// linker. See https://github.com/rust-lang/rust/issues/112586.
+//
+// Note that the `susroot_lib_path` returned by `target_filesearch().get_lib_path()` has
+// already had `fix_windows_verbatim_for_gcc()` applied if needed.
+fn rehome_sysroot_rlib_path<'a>(sess: &'a Session, rlib_path: PathBuf) -> PathBuf {
+    let sysroot_lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
+    let canonical_sysroot_lib_path =
+        { try_canonicalize(&sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) };
+
+    let mut canonical_rlib_dir = try_canonicalize(&rlib_path).unwrap_or_else(|_| rlib_path.clone());
+    canonical_rlib_dir.pop();
+
+    if canonical_rlib_dir == canonical_sysroot_lib_path {
+        sysroot_lib_path
+            .join(rlib_path.file_name().expect("rlib path has no file name path component"))
+    } else {
+        rlib_path
+    }
+}
+
 // Adds the static "rlib" versions of all crates to the command line.
 // There's a bit of magic which happens here specifically related to LTO,
 // namely that we remove upstream object files.
@@ -2713,7 +2738,7 @@ fn add_static_crate<'a>(
     let cratepath = &src.rlib.as_ref().unwrap().0;
 
     let mut link_upstream = |path: &Path| {
-        cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
+        cmd.link_rlib(&rehome_sysroot_rlib_path(sess, fix_windows_verbatim_for_gcc(path)));
     };
 
     if !are_upstream_rust_objects_already_included(sess)