Skip to content

Commit 40df2d2

Browse files
committed
Merge remote-tracking branch 'petrochenkov/link-modifiers'
2 parents 4c39f57 + a30650b commit 40df2d2

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed

text/0000-native-link-modifiers.md

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
- Feature Name: `native_link_modifiers`
2+
- Start Date: 2020-06-12
3+
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
4+
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Provide an extensible mechanism for tweaking linking behavior of native libraries
10+
both in `#[link]` attributes (`#[link(modifiers = "+foo,-bar")]`)
11+
and on command line (`-l static:+foo,-bar=mylib`).
12+
13+
# Motivation
14+
[motivation]: #motivation
15+
16+
Occasionally some tweaks to linking behavior of native libraries are necessary,
17+
and currently there's no way to apply them.
18+
19+
For example, some static libraries may need to be linked as a whole archive
20+
without throwing any object files away because some symbols in them appear to be unused
21+
while actually having some effect. \
22+
This RFC introduces modifier `whole-archive` to address this.
23+
24+
In other cases we need to link to a library located at some specific path
25+
or not matching the default naming conventions. \
26+
This RFC introduces modifier `verbatim` to pass such libraries to the linker.
27+
28+
This RFC also reformulates the `static-nobundle` linking kind as a modifier `bundle`
29+
thus providing an opportunity to change the static linking default to non-bundling
30+
on some future edition boundary, and hopefully unblocking its stabilization.
31+
32+
The generic syntax provides a way to add more such modifiers in the future
33+
without introducing new linking kinds.
34+
35+
# Guide-level explanation
36+
[guide-level-explanation]: #guide-level-explanation
37+
38+
This is an advanced feature not expected to be used commonly,
39+
see the reference-level explanation if you know that you need some of these modifiers.
40+
41+
# Reference-level explanation
42+
[reference-level-explanation]: #reference-level-explanation
43+
44+
## Existing syntax of linking attributes and options
45+
46+
- Attributes: `#[link(name = "string", kind = "string", cfg(predicate))]`
47+
(some components are optional.)
48+
- Command line options: `-l kind=name:rename` (some components are optional).
49+
50+
## Proposed extensions to the syntax
51+
52+
- Attributes: `#[link(/* same */, modifiers = "+foo,-bar")]`.
53+
- Command line options: `-l kind:+foo,-bar=name:rename`.
54+
55+
The modifiers are boolean and applied only to the single library specified with `name`. \
56+
`+` means enable, `-` means disable, multiple options can be separated by commas,
57+
the last boolean value specified for the given modifier wins. \
58+
The notation is borrowed from
59+
[target features](https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature)
60+
in general and should have the same semantics.
61+
62+
If the `:rename` component is specified on the command line, then in addition to the name
63+
and linking kind the modifiers will be updated as well (using concatenation).
64+
65+
## Specific modifiers
66+
67+
### `bundle`
68+
69+
Only compatible with the `static` linking kind.
70+
71+
`+bundle` means objects from the static library are bundled into the produced crate
72+
(a rlib, for example) and are used from this crate later during linking of the final binary.
73+
74+
`-bundle` means the static library is included into the produced rlib "by name"
75+
and object files from it are included only during linking of the final binary,
76+
the file search by that name is also performed during final linking.
77+
78+
This modifier is supposed to supersede the `static-nobundle` linking kind defined by
79+
[RFC 1717](https://github.com/rust-lang/rfcs/pull/1717).
80+
81+
The default for this modifier is currently `+bundle`,
82+
but it could be changed later on some future edition boundary.
83+
84+
### `verbatim`
85+
86+
`+verbatim` means that `rustc` itself won't add any target-specified library prefixes or suffixes
87+
(like `lib` or `.a`) to the library name,
88+
and will try its best to ask for the same thing from the linker.
89+
90+
For `ld`-like linkers `rustc` will use the `-l:filename` syntax (note the colon)
91+
when passing the library, so the linker won't add any prefixes or suffixes as well. \
92+
See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in `ld` documentation
93+
for more details. \
94+
For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`)
95+
the library name will be passed as is.
96+
97+
The default for this modifier is `-verbatim`.
98+
99+
This RFC changes the behavior of `raw-dylib` linking kind specified by
100+
[RFC 2627](https://github.com/rust-lang/rfcs/pull/2627).
101+
The `.dll` suffix (or other target-specified suffixes for other targets)
102+
is now added automatically. \
103+
If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`.
104+
105+
### `whole-archive`
106+
107+
Only compatible with the `static` linking kind.
108+
109+
`+whole-archive` means that the static library is linked as a whole archive
110+
without throwing any object files away.
111+
112+
This modifier translates to `--whole-archive` for `ld`-like linkers,
113+
to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`. \
114+
The modifier does nothing for linkers that don't support it.
115+
116+
The default for this modifier is `-whole-archive`.
117+
118+
A motivating example for this modifier can be found in
119+
[issue #56306](https://github.com/rust-lang/rust/issues/56306).
120+
121+
### `as-needed`
122+
123+
Only compatible with the `dynamic` and `framework` linking kinds.
124+
125+
`+as-needed` means that the library will be actually linked only if it satisfies some
126+
undefined symbols at the point at which it is specified on the command line,
127+
making it similar to static libraries in this regard.
128+
129+
This modifier translates to `--as-needed` for `ld`-like linkers,
130+
and to `-dead_strip_dylibs` / `-needed_library` / `-needed_framework` for `ld64`. \
131+
The modifier does nothing for linkers that don't support it (e.g. `link.exe`).
132+
133+
The default for this modifier is unclear, some targets currently specify it as `+as-needed`,
134+
some do not. We may want to try making `+as-needed` a default for all targets.
135+
136+
A motivating example for this modifier can be found in
137+
[issue #57837](https://github.com/rust-lang/rust/issues/57837).
138+
139+
## Stability story
140+
141+
The modifier syntax can be stabilized independently from any specific modifiers.
142+
143+
All the specific modifiers start unstable and can be stabilized independently from each other
144+
given enough demand.
145+
146+
## Relative order of `-l` and `-Clink-arg(s)` options
147+
148+
This RFC also proposes to guarantee that the relative order of `-l` and `-Clink-arg(s)`
149+
command line options of `rustc` is preserved when passing them to linker. \
150+
(Currently they are passed independently and the order is not guaranteed.)
151+
152+
This provides ability to tweak linking of individual libraries on the command line
153+
by using raw linker options. \
154+
An equivalent of order-preserving `-Clink-arg`, but in an attribute form,
155+
is not provided at this time.
156+
157+
# Drawbacks
158+
[drawbacks]: #drawbacks
159+
160+
Some extra complexity in parsing the modifiers
161+
and converting them into a form suitable for the linker.
162+
163+
Not all modifiers are applicable to all targets and linkers,
164+
but that's true for many existing `-C` options as well.
165+
166+
# Rationale and alternatives
167+
[rationale-and-alternatives]: #rationale-and-alternatives
168+
169+
170+
## Alternative: rely on raw linker options
171+
172+
The primary alternative for the (relatively cross-platform) `whole-archive` and `as-needed`
173+
modifiers is to rely on more target-specific raw linker options more.
174+
175+
(Note, that raw linker options don't cover the `bundle` and `verbatim` modifiers
176+
that are `rustc`-specific.)
177+
178+
The modifier support is removed from the command line options,
179+
the desired effect is achieved by something like this.
180+
```sh
181+
-Clink-arg=-Wl,--whole-archive -lfoo -Clink-arg=-Wl,--no-whole-archive
182+
```
183+
184+
Note the `-Wl,` that is needed when using `gcc` as a linker,
185+
but not when using an `ld`-like linker directly.
186+
So this solution is not only more target-specific, but also more linker specific as well.
187+
188+
The `-Wl,` part can potentially be added automatically though, there's some prior art from CMake
189+
regarding this, see the `LINKER:` modifier for
190+
[`target_link_options`](https://cmake.org/cmake/help/git-stage/command/target_link_options.html).
191+
192+
Relying on raw linker options while linking with attributes will requires introducing
193+
a new attribute, see the paragraph about `#[link(arg = "string")]` in "Future possibilities".
194+
195+
## Alternative: merge modifiers into kind in attributes
196+
197+
`#[link(kind = "static", modifiers = "+foo,-bar")]` -> `#[link(kind = "static:+foo,-bar")]`.
198+
199+
This make attributes closer to command line, but it's unclear whether it's a goal we want to pursue.
200+
For example, we already write `kind=name` on command line,
201+
but `kind = "...", name = "..."` in attributes.
202+
203+
# Prior art
204+
[prior-art]: #prior-art
205+
206+
`gcc` provides the `-Wl,foo` command line syntax (and some other similar options) for passing
207+
arbitrary options directly to the linker.
208+
209+
The relative order of `-Wl` options and `-l` options linking the libraries is preserved.
210+
211+
`cl.exe` provides `/link link-opts` for passing options directly to the linker,
212+
but the options supported by `link.exe` are generally order-independent,
213+
so it is not as relevant to modifying behavior of specific libraries as with `ld`-like linkers.
214+
215+
# Unresolved questions
216+
[unresolved-questions]: #unresolved-questions
217+
218+
None currently.
219+
220+
# Future possibilities
221+
[future-possibilities]: #future-possibilities
222+
223+
## New modifiers
224+
225+
### `dedup`
226+
227+
`rustc` doesn't currently deduplicate linked libraries
228+
[in general](https://github.com/rust-lang/rust/issues/73319).
229+
230+
The reason is that *sometimes* the linked libraries need to be duplicated on the command line.
231+
232+
However, such cases are rare and we may want to deduplicate the libraries by default,
233+
but provide the `-dedup` modifier as an opt-out for these rare cases.
234+
235+
Introducing the `dedup` modifier with the current `-dedup` default doesn't make much sense.
236+
237+
## Support `#[link(arg = "string")]` in addition to the modifiers
238+
239+
`ld` supports some other niche per-library options, for example `--copy-dt-needed-entries`.
240+
241+
`ld` also supports order-dependent options like `--start-group`/`--end-group`
242+
applying to groups of libraries.
243+
244+
We may want to avoid new modifiers for all possible cases like this and provide an order-preserving
245+
analogue of `-C link-arg`, but in the attribute form. \
246+
It may also resolve issues with the existing unstable attribute
247+
[`#[link_args]`](https://github.com/rust-lang/rust/issues/29596)
248+
and serve as its replacement.
249+
250+
Some analogue of
251+
[CMake's `LINKER:`](https://cmake.org/cmake/help/git-stage/command/target_link_options.html)
252+
mentioned above can improve portability here.

0 commit comments

Comments
 (0)