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