Skip to content

Commit ed9ef8e

Browse files
authored
Merge pull request #154 from amyspark/fix-windows-library-detection
Fix Windows static library detection and usage
2 parents 333771e + aafa1b2 commit ed9ef8e

File tree

1 file changed

+50
-27
lines changed

1 file changed

+50
-27
lines changed

src/lib.rs

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -776,34 +776,38 @@ impl Library {
776776
}
777777

778778
let prefix = "lib";
779-
if target.contains("msvc") {
780-
// According to link.exe documentation:
781-
// https://learn.microsoft.com/en-us/cpp/build/reference/link-input-files?view=msvc-170
782-
//
783-
// LINK doesn't use file extensions to make assumptions about the contents of a file.
784-
// Instead, LINK examines each input file to determine what kind of file it is.
785-
//
786-
// However, rustc appends `.lib` to the string it receives from the -l command line argument,
787-
// which it receives from Cargo via cargo:rustc-link-lib:
788-
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L828
789-
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L843
790-
// So the only file extension that works for MSVC targets is `.lib`
791-
return test_suffixes(filename, &[".lib"]);
792-
} else if target.contains("windows") && target.contains("gnu") {
793-
// GNU targets for Windows, including gnullvm, use `LinkerFlavor::Gcc` internally in rustc,
794-
// which tells rustc to use the GNU linker. rustc does not prepend/append to the string it
795-
// receives via the -l command line argument before passing it to the linker:
796-
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L446
797-
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L457
798-
// GNU ld can work with more types of files than just the .lib files that MSVC's link.exe needs.
799-
// GNU ld will prepend the `lib` prefix to the filename if necessary, so it is okay to remove
800-
// the `lib` prefix from the filename. The `.a` suffix *requires* the `lib` prefix.
801-
// https://sourceware.org/binutils/docs-2.39/ld.html#index-direct-linking-to-a-dll
802-
if filename.starts_with(prefix) {
779+
if target.contains("windows") {
780+
if target.contains("gnu") && filename.starts_with(prefix) {
781+
// GNU targets for Windows, including gnullvm, use `LinkerFlavor::Gcc` internally in rustc,
782+
// which tells rustc to use the GNU linker. rustc does not prepend/append to the string it
783+
// receives via the -l command line argument before passing it to the linker:
784+
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L446
785+
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L457
786+
// GNU ld can work with more types of files than just the .lib files that MSVC's link.exe needs.
787+
// GNU ld will prepend the `lib` prefix to the filename if necessary, so it is okay to remove
788+
// the `lib` prefix from the filename. The `.a` suffix *requires* the `lib` prefix.
789+
// https://sourceware.org/binutils/docs-2.39/ld.html#index-direct-linking-to-a-dll
803790
let filename = &filename[prefix.len()..];
804791
return test_suffixes(filename, &[".dll.a", ".dll", ".lib", ".a"]);
805792
} else {
806-
return test_suffixes(filename, &[".dll.a", ".dll", ".lib"]);
793+
// According to link.exe documentation:
794+
// https://learn.microsoft.com/en-us/cpp/build/reference/link-input-files?view=msvc-170
795+
//
796+
// LINK doesn't use file extensions to make assumptions about the contents of a file.
797+
// Instead, LINK examines each input file to determine what kind of file it is.
798+
//
799+
// However, rustc appends `.lib` to the string it receives from the -l command line argument,
800+
// which it receives from Cargo via cargo:rustc-link-lib:
801+
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L828
802+
// https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L843
803+
// So the only file extension that works for MSVC targets is `.lib`
804+
// However, for externally created libraries, there's no
805+
// guarantee that the extension is ".lib" so we need to
806+
// consider all options.
807+
// See:
808+
// https://github.com/mesonbuild/meson/issues/8153
809+
// https://github.com/rust-lang/rust/issues/114013
810+
return test_suffixes(filename, &[".dll.a", ".dll", ".lib", ".a"]);
807811
}
808812
} else if target.contains("apple") {
809813
if filename.starts_with(prefix) {
@@ -901,6 +905,10 @@ impl Library {
901905
iter.next().map(|s| s.to_owned()),
902906
);
903907
}
908+
"-u" => {
909+
let meta = format!("rustc-link-arg=-Wl,-u,{}", val);
910+
config.print_metadata(&meta);
911+
}
904912
_ => {}
905913
}
906914
}
@@ -927,6 +935,12 @@ impl Library {
927935
self.include_paths.push(PathBuf::from(inc));
928936
}
929937
}
938+
"-undefined" | "--undefined" => {
939+
if let Some(symbol) = iter.next() {
940+
let meta = format!("rustc-link-arg=-Wl,{},{}", part, symbol);
941+
config.print_metadata(&meta);
942+
}
943+
}
930944
_ => {
931945
let path = std::path::Path::new(part);
932946
if path.is_file() {
@@ -1000,10 +1014,19 @@ fn envify(name: &str) -> String {
10001014

10011015
/// System libraries should only be linked dynamically
10021016
fn is_static_available(name: &str, system_roots: &[PathBuf], dirs: &[PathBuf]) -> bool {
1003-
let libname = format!("lib{}.a", name);
1017+
let libnames = {
1018+
let mut names = vec![format!("lib{}.a", name)];
1019+
1020+
if cfg!(target_os = "windows") {
1021+
names.push(format!("{}.lib", name));
1022+
}
1023+
1024+
names
1025+
};
10041026

10051027
dirs.iter().any(|dir| {
1006-
!system_roots.iter().any(|sys| dir.starts_with(sys)) && dir.join(&libname).exists()
1028+
let library_exists = libnames.iter().any(|libname| dir.join(&libname).exists());
1029+
library_exists && !system_roots.iter().any(|sys| dir.starts_with(sys))
10071030
})
10081031
}
10091032

0 commit comments

Comments
 (0)