Skip to content

Commit 1fad337

Browse files
committed
Prefer system MinGW libs when available
1 parent b1cb3c0 commit 1fad337

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

src/librustc_codegen_ssa/back/link.rs

+78
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,78 @@ pub fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary
968968
}
969969
}
970970

971+
// Because windows-gnu target is meant to be self-contained for pure Rust code it bundles
972+
// own mingw-w64 libraries. These libraries are usually not compatible with mingw-w64
973+
// installed in the system. This breaks many cases where Rust is mixed with other languages
974+
// (e.g. *-sys crates).
975+
// We prefer system mingw-w64 libraries if they are available to avoid this issue.
976+
fn get_crt_libs_path(sess: &Session) -> Option<PathBuf> {
977+
fn find_exe_in_path<P>(exe_name: P) -> Option<PathBuf>
978+
where
979+
P: AsRef<Path>,
980+
{
981+
for dir in env::split_paths(&env::var_os("PATH")?) {
982+
let full_path = dir.join(&exe_name);
983+
if full_path.is_file() {
984+
return Some(fix_windows_verbatim_for_gcc(&full_path));
985+
}
986+
}
987+
None
988+
}
989+
990+
fn probe(sess: &Session) -> Option<PathBuf> {
991+
if let (linker, LinkerFlavor::Gcc) = linker_and_flavor(&sess) {
992+
let linker_path = if cfg!(windows) && linker.extension().is_none() {
993+
linker.with_extension("exe")
994+
} else {
995+
linker
996+
};
997+
if let Some(linker_path) = find_exe_in_path(linker_path) {
998+
let mingw_arch = match &sess.target.target.arch {
999+
x if x == "x86" => "i686",
1000+
x => x,
1001+
};
1002+
let mingw_dir = format!("{}-w64-mingw32", mingw_arch);
1003+
// Here we have path/bin/gcc but we need path/
1004+
let mut path = linker_path;
1005+
path.pop();
1006+
path.pop();
1007+
// Based on Clang MinGW driver
1008+
let probe_path = path.join(&mingw_dir).join("lib");
1009+
if probe_path.exists() {
1010+
return Some(probe_path);
1011+
};
1012+
let probe_path = path.join(&mingw_dir).join("sys-root/mingw/lib");
1013+
if probe_path.exists() {
1014+
return Some(probe_path);
1015+
};
1016+
};
1017+
};
1018+
None
1019+
}
1020+
1021+
let mut system_library_path = sess.system_library_path.borrow_mut();
1022+
match &*system_library_path {
1023+
Some(Some(compiler_libs_path)) => Some(compiler_libs_path.clone()),
1024+
Some(None) => None,
1025+
None => {
1026+
let path = probe(sess);
1027+
*system_library_path = Some(path.clone());
1028+
path
1029+
}
1030+
}
1031+
}
1032+
9711033
pub fn get_file_path(sess: &Session, name: &str) -> PathBuf {
1034+
// prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
1035+
if sess.target.target.llvm_target.contains("windows-gnu") {
1036+
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
1037+
let file_path = compiler_libs_path.join(name);
1038+
if file_path.exists() {
1039+
return file_path;
1040+
}
1041+
}
1042+
}
9721043
let fs = sess.target_filesearch(PathKind::Native);
9731044
let file_path = fs.get_lib_path().join(name);
9741045
if file_path.exists() {
@@ -1150,6 +1221,13 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
11501221
// target descriptor
11511222
let t = &sess.target.target;
11521223

1224+
// prefer system mingw-w64 libs, see get_crt_libs_path comment for more details
1225+
if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") {
1226+
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
1227+
cmd.include_path(&compiler_libs_path);
1228+
}
1229+
}
1230+
11531231
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
11541232

11551233
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {

src/librustc_session/session.rs

+5
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ pub struct Session {
133133
/// Mapping from ident span to path span for paths that don't exist as written, but that
134134
/// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
135135
pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
136+
137+
/// Path for libraries that will take preference over libraries shipped by Rust.
138+
/// Used by windows-gnu targets to priortize system mingw-w64 libraries.
139+
pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>,
136140
}
137141

138142
pub struct PerfStats {
@@ -1069,6 +1073,7 @@ fn build_session_(
10691073
driver_lint_caps,
10701074
trait_methods_not_found: Lock::new(Default::default()),
10711075
confused_type_with_std_module: Lock::new(Default::default()),
1076+
system_library_path: OneThread::new(RefCell::new(Default::default())),
10721077
};
10731078

10741079
validate_commandline_args_with_session_available(&sess);

0 commit comments

Comments
 (0)