8

Github Linking modifiers for native libraries by petrochenkov · Pull Request #29...

 3 years ago
source link: https://github.com/rust-lang/rfcs/pull/2951
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Conversation

Copy link

Contributor

petrochenkov commented on Jun 27, 2020

Provide some generic syntax (similar to target features) for linking modifiers used for native libraries.

Provide some specific modifiers to control bundling behavior, whole-archive and the library name mangling.

Copy link

Contributor

Author

petrochenkov commented on Jun 27, 2020

cc @retep998
I finally did what I promised in rust-lang/rust#72274 (comment).
Also note the library name change for raw-dylib.

undefined symbols at the point at which it is specified on the command line,

making it similar to static libraries in this regard.

This modifier translates to `--as-needed` for `ld`-like linkers.

retep998 on Jun 27, 2020

Member

Should add a sentence describing what this does for link.exe.

petrochenkov on Jun 27, 2020

edited

Author

Contributor

Will add (there's no MSVC equivalent, so it's ignored).

Notes from a Darwin (macOS/iOS/etc.) perspective:

Darwin uses ld64, which shares the basic syntax of a Unix linker but doesn't support these GNU ld options. Instead it has these equivalents:

  • verbatim: None. (Note that both GNU ld and ld64 support linking an arbitrarily-named library by passing the full path as a regular argument, but GNU ld's -l: searches the library path for an arbitrary filename, which ld64 doesn't seem to have any equivalent for.)
  • whole-archive: -all_load to enable for all, -force_load /path/to/foo.a to enable for a single library. rustc already supports this.
  • as-needed: -dead_strip_dylibs to enable by default, then (new in macOS 11) -needed-lx / -needed_library /path/to/library / -needed_framework framework to mark a single library as not "as needed".

What about the framework linking kind? What does it mean? What modifiers is it compatible with?

Frameworks are Darwin-specific and are literally identical to dylibs but with a different naming scheme and separate search paths.

  • -F/some/path is the equivalent of -L, but adding to the framework search paths rather than library search paths.
  • -framework Foo is the equivalent of -lfoo, but it uses the framework search paths and searches for something named Foo.framework/Foo rather than libfoo.dylib.

It should be compatible with the same modifiers as regular dylibs on Darwin.

Copy link

Contributor

Author

petrochenkov commented on Jun 28, 2020

@comex
Thanks!
"What about frameworks" in unresolved questions should have really been "What about Darwin".
I'll include this into the RFC.

Copy link

Contributor

Author

petrochenkov commented on Jun 28, 2020

edited

Note that both GNU ld and ld64 support linking an arbitrarily-named library by passing the full path as a regular argument

Without : the full path will still be "mangled", i.e. when passed -lmy/arbitrary/path ld will search for libmy/arbitrary/path.a or libmy/arbitrary/path.so.

[guide-level-explanation]: #guide-level-explanation

This is an advanced feature not expected to be used commonly,

see the reference-level explanation if you know that you need some of these modifiers.

clarfonthey on Jun 30, 2020

Contributor

I generally distinguish between guide and reference level for usage and implementation level, although I understand why you didn't bother here. It's not that big of a deal, but I just figured I'd mention this here in case people viewing get ideas. :p

on some future edition boundary, and hopefully unblocking its stabilization.

The generic syntax provides a way to add more such modifiers in the future

without introducing new linking kinds.

clarfonthey on Jun 30, 2020

Contributor

IMHO this section doesn't really provide that powerful of a motivation. If you've run into needing these issues before, it seems obvious, but I've personally never had to do any special linking despite having done a lot of work in C before. I feel like examples may be helpful, even if they're contrived.

petrochenkov on Jun 30, 2020

Author

Contributor

The GitHub issues linked from this PR provide some examples, I'll try to move them into the RFC.

The modifiers are boolean and applied only to the single library specified with `name`. \

`+` means enable, `-` means disable, multiple options can be separated by commas,

the last boolean value specified for the given modifier wins. \

clarfonthey on Jun 30, 2020

Contributor

Any reason to do this instead of erroring if multiple are specified?

petrochenkov on Jul 1, 2020

edited

Author

Contributor

To mirror target features mostly, there it's needed to override features on command line (rust-lang/rust#56527) so that -C target-feature=+keep,+change -C target-feature=-change becomes -C target-feature=+keep,+change,-change and becomes -C target-feature=+keep,-change.

(With linking modifiers it can also be used in theory, to override modifiers from attributes on command line, like
#[link(name = "mylib", modifiers = "+keep,+change")] + -l:-change=mylib:mylib which becomes -l:+keep,-change=mylib.)

clarfonthey on Jul 9, 2020

Contributor

Would it be possible to have a deny-by-default lint in code, then? Command line switches make perfect sense, but if someone includes multiple in the code it's almost certainly a mistake.

petrochenkov on Jul 22, 2020

Author

Contributor

Even if the multiple specifier case doesn't make sense, it's still very hard to write it accidentally, so making a new lint for it doesn't pull its weight. (There are plenty opportunities to write some unnatural code that doesn't make any sense but is not linted.)
I guess it's easier to make it a hard error then.

[RFC 1717](https://github.com/rust-lang/rfcs/pull/1717).

The default for this modifier is currently `+bundle`,

but it could be changed later on some future edition boundary.

clarfonthey on Jun 30, 2020

Contributor

If the whole point of editions is that you can link together code for multiple editions at once, wouldn't that not be a good idea?

petrochenkov on Jul 1, 2020

Author

Contributor

I don't think this change would break anything implicitly?
When a crate with #[link] attributes migrates from edition 202X to edition 202X+3 it will need to either add the modifier or change its build and/or distribution strategy. Both such such changes should be ok when a crate does edition bump.

is now added automatically. \

If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`.

### `whole-archive`

clarfonthey on Jun 30, 2020

Contributor

I feel like this name is a bit weird, because really it seems to be talking more about LTO. When reading "whole archive" my first thought is "why wouldn't the whole library be linked?"

petrochenkov on Jul 1, 2020

Author

Contributor

The logic behind both whole-archive and as-needed is to simply mirror the corresponding linker options.
Generally, if someone wants the "whole-archive" linking, then they probably want it to have the same name "whole-archive" for searchability.
On the other hand, if someone doesn't know what "whole-archive" means, then they probably don't need this option.

clarfonthey on Jul 9, 2020

Contributor

I'm personally viewing this from the perspective of someone looking at existing code to understand how it works. Documentation will include the options that they translate to for searchability, but I'm not sure someone would need to search for this in code itself.

The default for this modifier is `-whole-archive`.

### `as-needed`

clarfonthey on Jun 30, 2020

Contributor

Again, a bit fuzzy on the name here. Seems to be more of a statement about LTO.

For `ld`-like linkers `rustc` will use the `-l:filename` syntax (note the colon)

when passing the library, so the linker won't add any prefixes or suffixes as well. \

See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in `ld` documentation

for more details.

for more details. \

For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`)

retep998 on Jul 1, 2020

Member

link.exe is inherently verbatim, and it is Rust itself which adds any prefix/suffix. That is a significant difference compared to ld64.

petrochenkov on Jul 1, 2020

edited

Author

Contributor

Not entirely, link.exe will add .obj to files without extensions.
Also, the paragraph above talks about prefixes/suffixes added by rustc itself.

My idea here was "rustc passes what you passed to the linker without changes and the linker does what it wants with this input", not sure how to word this better.

Copy link

Contributor

nikomatsakis commented on Dec 2, 2020

We ended up adopting a similar plan in the form of a compiler-team major change proposal, rust-lang/compiler-team#356, so I'm going to close this RFC PR. =)

Copy link

Contributor

Author

petrochenkov commented on Jan 28

edited

@nikomatsakis
This RFC should have been merged, not closed.
The accepted "similar plan" literally says "merge this RFC".
Motivation: I want to refer to this RFC as a normative text when necessary, without explaining that "it may seem that the RFC was closed, but it was actually accepted, just through a different process" every time.

UPD: Tracking issue - rust-lang/rust#81490.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Assignees

No one assigned

Projects

None yet

Milestone

No milestone

Linked issues

Successfully merging this pull request may close these issues.

None yet

6 participants

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK