Closed Be-ing closed 1 year ago
I stumbled on this trying to statically link Qt built from vcpkg: https://github.com/KDAB/cxx-qt/pull/174
I'm not sure how to handle the build failure with Rust 1.30.0. Any suggestions how to keep this MSRV? Or raise the MSRV?
I think we should just update the MSRV. It's not sustainable to stay at an older version if the whole ecosystem moved on already.
The file matching is incorrectly strict.
On windows if you're using MSVC or MinGW or Clang, you can link to: libfoo.a
(static library built by Autotools with gcc or Meson with all compilers) or foo.lib
(import library or static library with visual studio project files or cmake).
If you are using Clang or GCC you can also link to libfoo.dll.a
(import library generated by GCC) or foo.dll
(directly to the DLL; not recommended, but possible with GCC and Clang). You can generate foo.lib
from libfoo.dll.a
if you want your mingw-built libraries to be linkable by MSVC, and people do that.
Cygwin is a whole other beast, with different file naming.
So maybe we should just search for (lib)?foo.(a|lib|lib.a|dll|dll.a)
here and be done with it?
(lib)?foo.(a|lib|lib.a|dll|dll.a)
I'm not sure it would be that simple. It depends if rustc-link-lib wants the lib
prefix or not and in which conditions.
I guess this then needs checking what rustc
actually expects/does here on Windows.
I suspect the linker used by rustc (lld or link or whatever) will accept whatever library you want to link to, if you use a full path.
The problem is that rustc
wants libraries separately as library-path / library-name AFAIU
How should we proceed here? Are you planning to check what rustc is doing @Be-ing ?
I'll dig into the rustc source code to get a clearer idea of how it works, unless someone beats me to that.
Reading the rustc source code, I found that there is an undocumented verbatim
modifier to the -l
option specifically for this use case. Unfortunately, it is still unstable. :disappointed:
A simpler solution: pass the file path to the linker with rustc-link-arg
instead of rustc-link-lib
.
Ah that looks nicely simple, thanks!
A simpler solution: pass the file path to the linker with rustc-link-arg instead of rustc-link-lib.
Unfortunately this won't work reliably because cargo doesn't transitively pass rustc-link-arg down to reverse dependencies.
I had a discussion with the developer working on the unstable +verbatim
option for rustc-link-lib
and he said that actually what we'd want is println!("cargo:rustc-link-lib=link-arg={lib_name}")
. The -l link-arg
option to rustc (passed from cargo via cargo:rustc-link-lib
) will be very similar to the existing -C link-arg
option (passed from cargo via cargo:rustc-link-arg
), however the important difference for the purposes of this PR is that Cargo transitively passes cargo:rustc-link-lib
to reverse dependencies, but not cargo:rustc-link-arg
(though I'm not certain that's intended).
For now, this is all still unstable, and I want to get this PR merged soon, so I think we'll have to go back to hacking around the platform-specific prefixes/suffixes that cargo:rustc-link-lib
adds.
That's disappointing but yes, let's do the complicated way then for now and hope this gets stabilized at some point.
Can you create an issue against cargo for that specific part?
Internally rustc gives each target a LinkerFlavor
which is converted to a Linker
by rustc_codgen_ssa::back::linker::get_linker
. The windows_gnu targets use LinkerFlavor::Gcc
(including the new gnullvm targets).
impl Linker for GccLinker
's link_dylib and link_staticlib methods pass the CLI arguments from rustc to the linker without prepending/appending anything.
impl Linker for MsvcLinker
's link_dylib and link_staticlib methods append .lib
to the CLI argument passed to rustc
GNU ld's documentation for Windows says:
when ld is called with the argument ‘-lxxx’ it will attempt to find, in the first directory of its search path,
libxxx.dll.a xxx.dll.a libxxx.a xxx.lib libxxx.lib cygxxx.dll (*) libxxx.dll xxx.dll
before moving on to the next directory in the search path.
Considering the linker will prepend lib
if necessary, it's fine to strip that prefix from the filename if it's present. So I think this regex would work: (lib)?(.*).(a|lib|dll|dll.a)
This is different from the msvc targets, so we do need separate regexes for #[cfg(not(all(windows, target_env = "gnu")))]
and #[cfg(not(all(windows, target_env = "msvc")))]
.
On windows if you're using MSVC or MinGW or Clang, you can link to: libfoo.a (static library built by Autotools with gcc or Meson with all compilers) or foo.lib (import library or static library with visual studio project files or cmake).
Even if MSVC is able to link to .a
files, rustc doesn't support that currently because it always appends .lib
.
Oof, using #[cfg]
attributes for this is wrong because that applies to the configuration of rustc when it's compiling the build script, not when running the build script, so I think it wouldn't work for cross compiling. I think the correct way to implement this platform-specific behavior is using the TARGET
environment variable.
I think the correct way to implement this platform-specific behavior is using the TARGET environment variable.
It depends on the case. Each cfg
comes through as an environment variable CARGO_CFG_{name}
: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts. (Note that for multi-valued cfg
s like target_feature
or target_family
this is a comma-separated list).
I think this is finally ready to merge.
I'll try and do a more thorough review on Monday or Tuesday (presumably by then https://github.com/rust-lang/team/pull/861#issuecomment-1286736563 will be done and I'll be able to actually land it if it's good). Initial impressions are fairly positive.
I'll go over this tomorrow but I'll wait then for @thomcc's review too early next week :)
Thanks for helping make this robust!
Could you publish a new release?
Could you publish a new release?
Sure, done :)
Typically pkgconfig files specify cflags for linking with -L and -l, however, pkgconfig files can also specify paths to library files. For example, building Qt5 statically on macOS generates the following pkgconfig file. Notice the absolute path to libqtpcre.a in Libs.private:
Building Qt5 statically on macOS with vcpkg generates this pkgconfig file which has a handful of file paths for libraries: