Skip to content

Commit 3392cc9

Browse files
committed
Auto merge of #67429 - mati865:mingw-ultimate-fix, r=<try>
windows-gnu: prefer system crt libraries if they are available This is my proposal (based on `Amanieu`'s idea) on how to fix #47048 and related issues. 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. I don't know if it's worth to cache system libraries path. You can look for `cache: ` string during build Rust: https://pastebin.com/kGEQZGWP I think there are enough calls to justify caching. Fixes #47048 Fixes #49078 Fixes #53454 Fixes #60912
2 parents b1cb3c0 + 229998b commit 3392cc9

File tree

4 files changed

+95
-2
lines changed

4 files changed

+95
-2
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3436,6 +3436,7 @@ dependencies = [
34363436
"bitflags",
34373437
"cc",
34383438
"jobserver",
3439+
"lazy_static 1.4.0",
34393440
"libc",
34403441
"log",
34413442
"memmap",

src/ci/azure-pipelines/try.yml

+13-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,19 @@ jobs:
1515
strategy:
1616
matrix:
1717
dist-x86_64-linux: {}
18-
dist-x86_64-linux-alt:
19-
IMAGE: dist-x86_64-linux
18+
- job: Windows
19+
timeoutInMinutes: 600
20+
pool:
21+
vmImage: 'vs2017-win2016'
22+
steps:
23+
- template: steps/run.yml
24+
strategy:
25+
matrix:
26+
dist-x86_64-mingw:
27+
SCRIPT: python x.py dist
28+
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
29+
CUSTOM_MINGW: 1
30+
DIST_REQUIRE_ALL_TOOLS: 1
2031

2132
# The macOS and Windows builds here are currently disabled due to them not being
2233
# overly necessary on `try` builds. We also don't actually have anything that

src/librustc_codegen_ssa/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ bitflags = "1.2.1"
1414
cc = "1.0.1"
1515
num_cpus = "1.0"
1616
memmap = "0.7"
17+
lazy_static = "1"
1718
log = "0.4.5"
1819
libc = "0.2.44"
1920
jobserver = "0.1.11"

src/librustc_codegen_ssa/back/link.rs

+80
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,81 @@ 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 often 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_some() {
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+
*SYSTEM_LIBS.lock().unwrap() = Some(Some(probe_path.clone()));
1011+
return Some(probe_path);
1012+
};
1013+
let probe_path = path.join(&mingw_dir).join("sys-root/mingw/lib");
1014+
if probe_path.exists() {
1015+
*SYSTEM_LIBS.lock().unwrap() = Some(Some(probe_path.clone()));
1016+
return Some(probe_path);
1017+
};
1018+
};
1019+
};
1020+
*SYSTEM_LIBS.lock().unwrap() = Some(None);
1021+
None
1022+
}
1023+
1024+
use std::sync::Mutex;
1025+
lazy_static::lazy_static! {
1026+
static ref SYSTEM_LIBS: Mutex<Option<Option<PathBuf>>> = Mutex::new(None);
1027+
}
1028+
1029+
let system_libs = SYSTEM_LIBS.lock().unwrap().clone();
1030+
match system_libs {
1031+
Some(Some(compiler_libs_path)) => Some(compiler_libs_path),
1032+
Some(None) => None,
1033+
None => probe(sess),
1034+
}
1035+
}
1036+
9711037
pub fn get_file_path(sess: &Session, name: &str) -> PathBuf {
1038+
if sess.target.target.llvm_target.contains("windows-gnu") {
1039+
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
1040+
let file_path = compiler_libs_path.join(name);
1041+
if file_path.exists() {
1042+
return file_path;
1043+
}
1044+
}
1045+
}
9721046
let fs = sess.target_filesearch(PathKind::Native);
9731047
let file_path = fs.get_lib_path().join(name);
9741048
if file_path.exists() {
@@ -1150,6 +1224,12 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
11501224
// target descriptor
11511225
let t = &sess.target.target;
11521226

1227+
if sess.target.target.llvm_target.contains("windows-gnu") {
1228+
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
1229+
cmd.include_path(&compiler_libs_path);
1230+
}
1231+
}
1232+
11531233
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
11541234

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

0 commit comments

Comments
 (0)