Auto merge of #67429 - mati865:mingw-ultimate-fix, r=alexcrichton
windows-gnu: prefer system crt libraries if they are available The origin of the issue is the fact Rust ships mingw-w64 libraries but no headers and prefers own libraries over the system ones. This leads to situation when headers aren't compatible with libraries (mingw-w64 doesn't provide any forward compatibility and AFAIK backwards compatibility is guaranteed only within major release series). It's easier to understand how this PR works when looking at the linker invocation before and with this PR: https://www.diffchecker.com/GEuYFmzo It adds system libraries path before Rust libraries so the linker will prefer them. It has potential issue when system has files with the same names as Rust but that could be avoided by moving Rust shipped mingw-w64 libraries from `lib/rustlib/x86_64-pc-windows-gnu/lib` to say `lib/rustlib/x86_64-pc-windows-gnu/lib/mingw`. Then adding linker paths in this order: Rust libraries, system libraries, Rust shipped mingw-w64 libraries. Fixes #47048 Fixes #49078 Fixes #53454 Fixes #60912
This commit is contained in:
commit
58b834344f
@ -968,7 +968,78 @@ pub fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary
|
||||
}
|
||||
}
|
||||
|
||||
// Because windows-gnu target is meant to be self-contained for pure Rust code it bundles
|
||||
// own mingw-w64 libraries. These libraries are usually not compatible with mingw-w64
|
||||
// installed in the system. This breaks many cases where Rust is mixed with other languages
|
||||
// (e.g. *-sys crates).
|
||||
// We prefer system mingw-w64 libraries if they are available to avoid this issue.
|
||||
fn get_crt_libs_path(sess: &Session) -> Option<PathBuf> {
|
||||
fn find_exe_in_path<P>(exe_name: P) -> Option<PathBuf>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
for dir in env::split_paths(&env::var_os("PATH")?) {
|
||||
let full_path = dir.join(&exe_name);
|
||||
if full_path.is_file() {
|
||||
return Some(fix_windows_verbatim_for_gcc(&full_path));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn probe(sess: &Session) -> Option<PathBuf> {
|
||||
if let (linker, LinkerFlavor::Gcc) = linker_and_flavor(&sess) {
|
||||
let linker_path = if cfg!(windows) && linker.extension().is_none() {
|
||||
linker.with_extension("exe")
|
||||
} else {
|
||||
linker
|
||||
};
|
||||
if let Some(linker_path) = find_exe_in_path(linker_path) {
|
||||
let mingw_arch = match &sess.target.target.arch {
|
||||
x if x == "x86" => "i686",
|
||||
x => x,
|
||||
};
|
||||
let mingw_dir = format!("{}-w64-mingw32", mingw_arch);
|
||||
// Here we have path/bin/gcc but we need path/
|
||||
let mut path = linker_path;
|
||||
path.pop();
|
||||
path.pop();
|
||||
// Based on Clang MinGW driver
|
||||
let probe_path = path.join(&mingw_dir).join("lib");
|
||||
if probe_path.exists() {
|
||||
return Some(probe_path);
|
||||
};
|
||||
let probe_path = path.join(&mingw_dir).join("sys-root/mingw/lib");
|
||||
if probe_path.exists() {
|
||||
return Some(probe_path);
|
||||
};
|
||||
};
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
let mut system_library_path = sess.system_library_path.borrow_mut();
|
||||
match &*system_library_path {
|
||||
Some(Some(compiler_libs_path)) => Some(compiler_libs_path.clone()),
|
||||
Some(None) => None,
|
||||
None => {
|
||||
let path = probe(sess);
|
||||
*system_library_path = Some(path.clone());
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_file_path(sess: &Session, name: &str) -> PathBuf {
|
||||
// prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
|
||||
if sess.target.target.llvm_target.contains("windows-gnu") {
|
||||
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
|
||||
let file_path = compiler_libs_path.join(name);
|
||||
if file_path.exists() {
|
||||
return file_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
let fs = sess.target_filesearch(PathKind::Native);
|
||||
let file_path = fs.get_lib_path().join(name);
|
||||
if file_path.exists() {
|
||||
@ -1150,6 +1221,13 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
|
||||
// target descriptor
|
||||
let t = &sess.target.target;
|
||||
|
||||
// prefer system mingw-w64 libs, see get_crt_libs_path comment for more details
|
||||
if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") {
|
||||
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
|
||||
cmd.include_path(&compiler_libs_path);
|
||||
}
|
||||
}
|
||||
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
|
||||
|
||||
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
|
||||
|
@ -132,6 +132,10 @@ pub struct Session {
|
||||
/// Mapping from ident span to path span for paths that don't exist as written, but that
|
||||
/// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
|
||||
pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
|
||||
|
||||
/// Path for libraries that will take preference over libraries shipped by Rust.
|
||||
/// Used by windows-gnu targets to priortize system mingw-w64 libraries.
|
||||
pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>,
|
||||
}
|
||||
|
||||
pub struct PerfStats {
|
||||
@ -1068,6 +1072,7 @@ fn build_session_(
|
||||
driver_lint_caps,
|
||||
trait_methods_not_found: Lock::new(Default::default()),
|
||||
confused_type_with_std_module: Lock::new(Default::default()),
|
||||
system_library_path: OneThread::new(RefCell::new(Default::default())),
|
||||
};
|
||||
|
||||
validate_commandline_args_with_session_available(&sess);
|
||||
|
Loading…
x
Reference in New Issue
Block a user