rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.26k stars 12.71k forks source link

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

Open petrochenkov opened 2 years ago

petrochenkov commented 2 years ago

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" (https://github.com/rust-lang/rust/issues/81490, https://github.com/rust-lang/rfcs/pull/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 https://github.com/rust-lang/rust/issues/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

petrochenkov commented 2 years ago

Implemented in https://github.com/rust-lang/rust/pull/99467.

petrochenkov commented 2 years ago

There's one possible improvement to -l link-arg making it more portable between linkers and useful - befriending it with the verbatim modifier (https://github.com/rust-lang/rust/issues/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

Be-ing commented 2 years ago

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?

petrochenkov commented 2 years ago

@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 https://github.com/rust-lang/rust/issues/99427#issuecomment-1234443468, 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).

Be-ing commented 1 year ago

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.

petrochenkov commented 11 months ago

Update: https://github.com/rust-lang/rust/pull/118202 implemented the new behavior for -l link-arg (https://github.com/rust-lang/rust/issues/99427#issuecomment-1234443468), 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.

madsmtm commented 11 months ago

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")]?

petrochenkov commented 11 months ago

@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.

madsmtm commented 11 months ago

Cool, thanks, I've submitted a test for this in https://github.com/rust-lang/rust/pull/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).

madsmtm commented 11 months ago

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