rust-lang/rust

Tracking Issue for linker arguments respecting their relative order with `-l` library options

petrochenkov opened this issue · 10 comments

This is a tracking issue for link arguments respecting their relative order with -l library options, which is a part of RFC "Linking modifiers for native libraries" (#81490, rust-lang/rfcs#2951), https://github.com/rust-lang/rfcs/blob/master/text/2951-native-link-modifiers.md#relative-order-of--l-and--clink-args-options specifically.
There's no feature gate for the issue.

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Steps

Unresolved Questions

The feature is unlikely to be implementable in the form that is specified in the RFC, i.e. by preserving relative order of -l and -Clink-arg(s) options.
-C link-arg was usable for overriding options previously passed by the compiler for long time, so is pretty much guaranteed to be passed at the end of command line at this point.

The suggested solution (see #81490 and below) is to reuse the -l option for such arguments and introduce -l link-arg=arbitrary-link-argument, which is exactly like -C link-arg=arbitrary-link-argument, except that its relative order to other -l options is respected.

Implementation history

Implemented in #99467.

There's one possible improvement to -l link-arg making it more portable between linkers and useful - befriending it with the verbatim modifier (#99425).

-l link-arg:-verbatim=-foo would add -Wl,-foo (or equivalent) when C compiler is used as a linker, and just -foo when bare linker is used.
-l link-arg:+verbatim=-bar on the other hand would always pass just -bar.
Not sure about the default here, I suspect that -verbatim would be preferable, but it's different from -C link-arg.

This would help to make link-arg usable in #[link] attributes and e.g. wrap libc and libgcc into a group (*) in the libc crate like

#[link(kind = "link-arg", name = "--start-group")]
#[link(kind = "static", name = "c")]
#[link(kind = "static", name = "gcc")]
#[link(kind = "link-arg", name = "--end-group")]

(*) to address cyclic dependencies between them

This is an analogue of CMake's LINKER: prefix (https://cmake.org/cmake/help/git-stage/command/target_link_options.html#handling-compiler-driver-differences), and was discussed as a possible future extension in the link modifier RFC (https://github.com/rust-lang/rfcs/blob/master/text/2951-native-link-modifiers.md#support-linkarg--string-in-addition-to-the-modifiers).

cc @krasimirgg

I think -l link-arg may have an unintended side effect: when build scripts run println!("cargo:rustc-link-lib={some_value}") to get cargo to call rustc with -l, cargo transitively passes the -l some_value down to the crates' reverse dependencies. By contrast, using the recently stabilized cargo:rustc-link-arg, which passes -C link-arg to rustc, cargo does not pass the linker argument down to reverse dependencies. I think this would be useful, but is this desired?

@Be-ing
It's better to ask the cargo questions on the cargo repo, but in case of rustc -l link-args are supposed to be passed from rlibs to the final linking step in the same way as other -l options, to address the use case from #99427 (comment), for example (libc crate adds --(start,end)-group, but they are actually passed to the linker later when libc crate is used as a dependency of an executable or dynamic library).

What is needed to move this forward? I have run into another situation in which -l link-arg is needed. When linking Qt6Quick statically, some .cpp.o files (compiled from a file generated by Qt's rcc tool) need to be linked too, but there's no stable interface to tell rustc and cargo to link those. I have tried using

println!("cargo:rustc-link-lib=static:+verbatim=/home/be/qt6-installed/lib/objects-Release/Quick_resources_2/.rcc/qrc_scenegraph_shaders.cpp.o");

but that fails with file too small to be an archive, an error that comes from LLVM. When implementing support for linking file paths in the pkg-config crate, I could hack around the lack of -l link-arg by splitting the path into the parent directory and file name then passing those with -L and -l, but that doesn't work for .o files because of this file too small to be an archive error.

Update: #118202 implemented the new behavior for -l link-arg (#99427 (comment)), now it adds -Wl, to the passed linker flags automatically if the linker is a C/C++ compiler.

This may be a breaking change for the current users of -l link-arg.

If some flag needs to be passed specifically to the C/C++ compiler, and not to the underlying linker, then the +verbatim modifier can be used - -l link-arg:+verbatim=-nostartfiles.

Is this intended to also be used to weakly link frameworks on Apple platforms? As in, the equivalent of -weak_framework CoreFoundation would be to do the following:

#![feature(link_arg_attribute)]

#[link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim")]
#[link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")]
extern "C" {}

Or must this be implemented separately as #[link(name = "CoreFoundation", kind = "weak_framework")]?

@madsmtm
link-arg is supposed to cover any cases that are not natively supported by existing link kinds at the moment (https://github.com/rust-lang/rfcs/blob/master/text/2951-native-link-modifiers.md#support-linkarg--string-in-addition-to-the-modifiers).
The -weak_framework seems to fit that description, although I'm not personally familiar with it.

Cool, thanks, I've submitted a test for this in #118644.

(I actually think it works exactly like "framework" (rustc_session::utils::NativeLibKind::Framework), which seems to suggest it may need to be +verbatim to be completely correct; I've updated my previous post).

Also tagging @grovesNL, you asked about this functionality a while ago on this internals thread.