From 73d776dfbfa3682c785fdd0aa99d34f74ba8bf6d Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Mon, 21 Aug 2023 14:59:01 -0300 Subject: [PATCH 1/3] Library: Allow using Meson-built Windows libraries Although there's a clear MSVC convention of calling import libraries "xxxx.lib", when a build system creates both static and shared libraries, a race condition will be caused [1]. To this end, the Meson build system decided to also apply the GNU convention for the MSVC ABI [2], which is not considered in pkg-config-rs. [1]: https://aomedia-review.googlesource.com/c/aom/+/173603 [2]: https://github.com/mesonbuild/meson/issues/8153 --- src/lib.rs | 54 +++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ccffd74..e81cefb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -776,34 +776,38 @@ impl Library { } let prefix = "lib"; - if target.contains("msvc") { - // According to link.exe documentation: - // https://learn.microsoft.com/en-us/cpp/build/reference/link-input-files?view=msvc-170 - // - // LINK doesn't use file extensions to make assumptions about the contents of a file. - // Instead, LINK examines each input file to determine what kind of file it is. - // - // However, rustc appends `.lib` to the string it receives from the -l command line argument, - // which it receives from Cargo via cargo:rustc-link-lib: - // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L828 - // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L843 - // So the only file extension that works for MSVC targets is `.lib` - return test_suffixes(filename, &[".lib"]); - } else if target.contains("windows") && target.contains("gnu") { - // GNU targets for Windows, including gnullvm, use `LinkerFlavor::Gcc` internally in rustc, - // which tells rustc to use the GNU linker. rustc does not prepend/append to the string it - // receives via the -l command line argument before passing it to the linker: - // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L446 - // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L457 - // GNU ld can work with more types of files than just the .lib files that MSVC's link.exe needs. - // GNU ld will prepend the `lib` prefix to the filename if necessary, so it is okay to remove - // the `lib` prefix from the filename. The `.a` suffix *requires* the `lib` prefix. - // https://sourceware.org/binutils/docs-2.39/ld.html#index-direct-linking-to-a-dll - if filename.starts_with(prefix) { + if target.contains("windows") { + if target.contains("gnu") && filename.starts_with(prefix) { + // GNU targets for Windows, including gnullvm, use `LinkerFlavor::Gcc` internally in rustc, + // which tells rustc to use the GNU linker. rustc does not prepend/append to the string it + // receives via the -l command line argument before passing it to the linker: + // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L446 + // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L457 + // GNU ld can work with more types of files than just the .lib files that MSVC's link.exe needs. + // GNU ld will prepend the `lib` prefix to the filename if necessary, so it is okay to remove + // the `lib` prefix from the filename. The `.a` suffix *requires* the `lib` prefix. + // https://sourceware.org/binutils/docs-2.39/ld.html#index-direct-linking-to-a-dll let filename = &filename[prefix.len()..]; return test_suffixes(filename, &[".dll.a", ".dll", ".lib", ".a"]); } else { - return test_suffixes(filename, &[".dll.a", ".dll", ".lib"]); + // According to link.exe documentation: + // https://learn.microsoft.com/en-us/cpp/build/reference/link-input-files?view=msvc-170 + // + // LINK doesn't use file extensions to make assumptions about the contents of a file. + // Instead, LINK examines each input file to determine what kind of file it is. + // + // However, rustc appends `.lib` to the string it receives from the -l command line argument, + // which it receives from Cargo via cargo:rustc-link-lib: + // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L828 + // https://github.com/rust-lang/rust/blob/657f246812ab2684e3c3954b1c77f98fd59e0b21/compiler/rustc_codegen_ssa/src/back/linker.rs#L843 + // So the only file extension that works for MSVC targets is `.lib` + // However, for externally created libraries, there's no + // guarantee that the extension is ".lib" so we need to + // consider all options. + // See: + // https://github.com/mesonbuild/meson/issues/8153 + // https://github.com/rust-lang/rust/issues/114013 + return test_suffixes(filename, &[".dll.a", ".dll", ".lib", ".a"]); } } else if target.contains("apple") { if filename.starts_with(prefix) { From e37f666e791fc89a3f8e4ab4544bfac59964c3c2 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Mon, 21 Aug 2023 15:02:33 -0300 Subject: [PATCH 2/3] is_static_available: Also consider Windows MSVC libraries for dynamic linkage --- src/lib.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e81cefb..54247fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1004,10 +1004,19 @@ fn envify(name: &str) -> String { /// System libraries should only be linked dynamically fn is_static_available(name: &str, system_roots: &[PathBuf], dirs: &[PathBuf]) -> bool { - let libname = format!("lib{}.a", name); + let libnames = { + let mut names = vec![format!("lib{}.a", name)]; + + if cfg!(target_os = "windows") { + names.push(format!("{}.lib", name)); + } + + names + }; dirs.iter().any(|dir| { - !system_roots.iter().any(|sys| dir.starts_with(sys)) && dir.join(&libname).exists() + let library_exists = libnames.iter().any(|libname| dir.join(&libname).exists()); + library_exists && !system_roots.iter().any(|sys| dir.starts_with(sys)) }) } From aafa1b2d22a2a9c2e7afbea74c8b4421cd8f35dd Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Mon, 21 Aug 2023 19:49:38 -0300 Subject: [PATCH 3/3] Allow passing -Wl,-u to the linker --- src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 54247fd..62b26f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -905,6 +905,10 @@ impl Library { iter.next().map(|s| s.to_owned()), ); } + "-u" => { + let meta = format!("rustc-link-arg=-Wl,-u,{}", val); + config.print_metadata(&meta); + } _ => {} } } @@ -931,6 +935,12 @@ impl Library { self.include_paths.push(PathBuf::from(inc)); } } + "-undefined" | "--undefined" => { + if let Some(symbol) = iter.next() { + let meta = format!("rustc-link-arg=-Wl,{},{}", part, symbol); + config.print_metadata(&meta); + } + } _ => { let path = std::path::Path::new(part); if path.is_file() {