@@ -10,15 +10,16 @@ Enable the compiler to select whether a target dynamically or statically links
10
10
to a platform's standard C runtime through the introduction of three orthogonal
11
11
and otherwise general purpose features, one of which will likely never become
12
12
stable and can be considered an implementation detail of std. These features do
13
- not require rustc to have intrinsic knowledge of the existence of C runtimes.
13
+ not require the compiler or language to have intrinsic knowledge of the
14
+ existence of C runtimes.
14
15
15
16
The end result is that rustc will be able to reuse its existing standard library
16
- binaries for the MSVC and musl targets for building code that links either
17
+ binaries for the MSVC and musl targets to build code that links either
17
18
statically or dynamically to libc.
18
19
19
20
The design herein additionally paves the way for improved support for
20
- dllimport/dllexport and cpu-specific features, particularly when combined with a
21
- [ std-aware cargo] .
21
+ dllimport/dllexport, and cpu-specific features, particularly when
22
+ combined with a [ std-aware cargo] .
22
23
23
24
[ std-aware cargo ] : https://github.com/rust-lang/rfcs/pull/1133
24
25
@@ -30,8 +31,8 @@ example the `x86_64-unknown-linux-gnu` target links to glibc dynamically,
30
31
` x86_64-unknown-linux-musl ` links statically to musl, and
31
32
` x86_64-pc-windows-msvc ` links dynamically to MSVCRT. There are many use cases,
32
33
however, where these decisions are not suitable. For example binaries on Alpine
33
- Linux want to link dynamically to musl and redistributable binaries on Windows
34
- are best done by linking statically to MSVCRT.
34
+ Linux want to link dynamically to musl and creating portable binaries on Windows
35
+ is most easily done by linking statically to MSVCRT.
35
36
36
37
Today rustc has no mechanism for accomplishing this besides defining an entirely
37
38
new target specification and distributing a build of the standard library for
@@ -42,10 +43,10 @@ fit, we have resisted doing so.
42
43
# Detailed design
43
44
[ design ] : #detailed-design
44
45
45
- This RFC introduces three separate features to the compiler and Cargo. When
46
- combined together they will enable the compiler to change whether the C standard
47
- library is linked dynamically or statically. In isolation each feature is a
48
- natural extension of existing features, should be useful on their own.
46
+ This RFC introduces three separate features to the compiler and Cargo. When
47
+ combined they will enable the compiler to change whether the C standard library
48
+ is linked dynamically or statically. In isolation each feature is a natural
49
+ extension of existing features, and each should be useful on its own.
49
50
50
51
A key insight is that, for practical purposes, the object code _ for the standard
51
52
library_ does not need to change based on how the C runtime is being linked;
@@ -66,11 +67,12 @@ requirement.
66
67
67
68
From these observations we can design a cross-platform solution spanning both
68
69
Cargo and the compiler by which Rust programs may link to either a dynamic or
69
- static C library, using only a single std binary. As future work it discusses
70
- how the proposed scheme scheme can be extended to rebuild std specifically for a
71
- particular C-linkage scenario, which may have minor advantages on Windows due to
72
- issues around dllimport and dllexport; and how this scheme naturally extends
73
- to recompiling std in the presence of modified CPU features.
70
+ static C library, using only a single std binary. As future work this RFC
71
+ discusses how the proposed scheme scheme can be extended to rebuild std
72
+ specifically for a particular C-linkage scenario, which may have minor
73
+ advantages on Windows due to issues around dllimport and dllexport; and how this
74
+ scheme naturally extends to recompiling std in the presence of modified CPU
75
+ features.
74
76
75
77
This RFC does * not* propose unifying how the C runtime is linked across
76
78
platforms (e.g. always dynamically or always statically) but instead leaves that
@@ -89,8 +91,8 @@ In summary the new mechanics are:
89
91
enable build scripts to understand all enabled features of a target (like
90
92
` crt-static ` above) to, for example, compile C code correctly on MSVC.
91
93
- Lazy link attributes. This feature is only required by std's own copy of the
92
- libc crate, since std is distributed in binary form, and it may yet be a long
93
- time before Cargo itself can rebuild std.
94
+ libc crate, and only because std is distributed in binary form and it may yet
95
+ be a long time before Cargo itself can rebuild std.
94
96
95
97
### Specifying dynamic/static C runtime linkage
96
98
@@ -105,7 +107,7 @@ rustc -C target-feature=-crt-static ...
105
107
Currently all ` target-feature ` flags are passed through straight to LLVM, but
106
108
this proposes extending the meaning of ` target-feature ` to Rust-target-specific
107
109
features as well. Target specifications will be able to indicate what custom
108
- target-features can be defined, and most existing target will define a new
110
+ target-features can be defined, and most existing targets will define a new
109
111
` crt-static ` feature which is turned off by default (except for musl).
110
112
111
113
The default of ` crt-static ` will be different depending on the target. For
@@ -114,10 +116,10 @@ example `x86_64-unknown-linux-musl` will have it on by default, whereas
114
116
115
117
### Lowering ` cfg ` values to Cargo build script environment variables
116
118
117
- Cargo will begin to forward ` #[ cfg] ` directives from the compiler into build
119
+ Cargo will begin to forward ` cfg ` values from the compiler into build
118
120
scripts. Currently the compiler supports ` --print cfg ` as a flag to print out
119
- internal cfg directives, which Cargo currently uses to implement
120
- platform-specific dependencies.
121
+ internal cfg directives, which Cargo uses to implement platform-specific
122
+ dependencies.
121
123
122
124
When Cargo runs a build script it already sets a [ number of environment
123
125
variables] [ cargo-build-env ] , and it will now set a family of ` CARGO_CFG_* `
@@ -154,10 +156,11 @@ export CARGO_CFG_UNIX
154
156
export CARGO_CFG_DEBUG_ASSERTIONS
155
157
```
156
158
157
- As mentioned in the previous section, the linkage of the C standard library
158
- will be specified as a target feature, which is lowered to a ` cfg ` value.
159
- One important complication here is that ` cfg ` values in Rust may be defined
160
- multiple times, and this is the case with target features. When a
159
+ As mentioned in the previous section, the linkage of the C standard library will
160
+ be specified as a target feature, which is lowered to a ` cfg ` value, thus giving
161
+ build scripts the ability to modify compilation options based on C standard
162
+ library linkage. One important complication here is that ` cfg ` values in Rust
163
+ may be defined multiple times, and this is the case with target features. When a
161
164
` cfg ` value is defined multiple times, Cargo will create a single environment
162
165
variable with a comma-separated list of values.
163
166
@@ -186,40 +189,47 @@ for the C code they might be compiling.
186
189
After this change, the gcc-rs crate will be modified to check for the
187
190
` CARGO_CFG_TARGET_FEATURE ` directive, and parse it into a list of enabled
188
191
features. If the ` crt-static ` feature is not enabled it will compile C code on
189
- the MSVC target with ` /MD ` . Otherwise if the value is ` static ` it will compile
190
- code with ` /MT ` .
192
+ the MSVC target with ` /MD ` , indicating dynamic linkage. Otherwise if the value
193
+ is ` static ` it will compile code with ` /MT ` , indicating static linkage. Because
194
+ today the MSVC targets use dynamic linkage and gcc-rs compiles C code with ` /MD ` ,
195
+ gcc-rs will remain forward and backwards compatible with existing and future
196
+ Rust MSVC toolchains until such time as the the decision is made to change the
197
+ MSVC toolchain to ` +crt-static ` by default.
191
198
192
199
### Lazy link attributes
193
200
194
201
The final feature that will be added to the compiler is the ability to "lazily"
195
- link a native library depending on values of ` #[cfg] ` at compile time of
196
- downstream crates, not of the crate with the ` #[link] ` directives. This feature
197
- is never intended to be stabilized, and is instead targeted at being an unstable
198
- implementation detail of the ` libc ` crate.
202
+ interpret the linkage requirements of a native library depending on values of
203
+ ` cfg ` at compile time of downstream crates, not of the crate with the ` #[link] `
204
+ directives. This feature is never intended to be stabilized, and is instead
205
+ targeted at being an unstable implementation detail of the ` libc ` crate linked
206
+ to ` std ` (but _ not_ the stable ` libc ` crate deployed to crates.io).
199
207
200
- Specifically, the ` #[link] ` attribute will be extended with a new directive
208
+ Specifically, the ` #[link] ` attribute will be extended with a new argument
201
209
that it accepts, ` cfg(..) ` , such as:
202
210
203
211
``` rust
204
212
#[link(name = " foo" , cfg(bar))]
205
213
```
206
214
207
215
This ` cfg ` indicates to the compiler that the ` #[link] ` annotation only applies
208
- if the ` bar ` directive is matched. The compiler will then use this knowledge
209
- in two ways:
216
+ if the ` bar ` directive is matched. This interpretation is done not during
217
+ compilation of the crate in which the ` #[link] ` directive appears, but during
218
+ compilation of the crate in which linking is finally performed. The compiler
219
+ will then use this knowledge in two ways:
210
220
211
221
* When ` dllimport ` or ` dllexport ` needs to be applied, it will evaluate the
212
- current compilation's ` #[cfg] ` directives and see if upstream ` #[link] `
222
+ final compilation unit 's ` #[cfg] ` directives and see if upstream ` #[link] `
213
223
directives apply or not.
214
224
215
225
* When deciding what native libraries should be linked, the compiler will
216
- evaluate whether they should be linked or not depending on the current
226
+ evaluate whether they should be linked or not depending on the final
217
227
compilation's ` #[cfg] ` directives and the upstream ` #[link] ` directives.
218
228
219
229
### Customizing linkage to the C runtime
220
230
221
- With the above features, the following changes will be made to enable selecting
222
- the linkage of the C runtime at compile time for downstream crates.
231
+ With the above features, the following changes will be made to select the
232
+ linkage of the C runtime at compile time for downstream crates.
223
233
224
234
First, the ` libc ` crate will be modified to contain blocks along the lines of:
225
235
@@ -239,14 +249,14 @@ cfg_if! {
239
249
}
240
250
```
241
251
242
- This informs the compiler that for the musl target if the CRT is statically
252
+ This informs the compiler that, for the musl target, if the CRT is statically
243
253
linked then the library named ` c ` is included statically in libc.rlib. If the
244
254
CRT is linked dynamically, however, then the library named ` c ` will be linked
245
255
dynamically. Similarly for MSVC, a static CRT implies linking to ` libcmt ` and a
246
256
dynamic CRT implies linking to ` msvcrt ` (as we do today).
247
257
248
- Finally, an example of compiling for MSVC linking statically to the C runtime
249
- would look like:
258
+ Finally, an example of compiling for MSVC and linking statically to the C
259
+ runtime would look like:
250
260
251
261
```
252
262
RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-pc-windows-msvc
@@ -273,7 +283,7 @@ Furthermore, it would have arguably been a "more correct" choice for Rust to by
273
283
default statically link to the CRT on MSVC rather than dynamically. While this
274
284
would be a breaking change today due to how C components are compiled, if this
275
285
RFC is implemented it should not be a breaking change to switch the defaults in
276
- the future.
286
+ the future, after a reasonable transition period .
277
287
278
288
The support in this RFC implies that the exact artifacts that we're shipping
279
289
will be usable for both dynamically and statically linking the CRT.
@@ -286,6 +296,21 @@ feature would simply be another input to this logic, so Cargo would
286
296
custom-compile the standard library if it differed from the upstream artifacts,
287
297
solving this problem.
288
298
299
+ ### References
300
+
301
+ - [ Issue about MSVCRT static linking]
302
+ (https://github.com/rust-lang/libc/issues/290 )
303
+ - [ Issue about musl dynamic linking]
304
+ (https://github.com/rust-lang/rust/issues/34987 )
305
+ - [ Discussion on issues around glgobal codegen configuration]
306
+ (https://internals.rust-lang.org/t/pre-rfc-a-vision-for-platform-architecture-configuration-specific-apis/3502 )
307
+ - [ std-aware Cargo RFC]
308
+ (https://github.com/rust-lang/libc/issues/290 ).
309
+ A proposal to teach Cargo to build the standard library. Rebuilding of std will
310
+ likely in the future be influenced by ` -C target-feature ` .
311
+ - [ Cargo's documentation on build-script environment variables]
312
+ (https://github.com/rust-lang/libc/issues/290 )
313
+
289
314
# Drawbacks
290
315
[ drawbacks ] : #drawbacks
291
316
@@ -300,6 +325,11 @@ solving this problem.
300
325
targets the ` --cfg crt_link=... ` directive affects the linkage of the CRT,
301
326
which seems like a worthy goal regardless.
302
327
328
+ * The lazy semantics of ` #[link(cfg(..))] ` are not so obvious from the name (no
329
+ other ` cfg ` attribute is treated this way). But this seems a minor issue since
330
+ the feature serves one implementation-specif purpose and isn't intended for
331
+ stabilization.
332
+
303
333
# Alternatives
304
334
[ alternatives ] : #alternatives
305
335
@@ -320,6 +350,15 @@ solving this problem.
320
350
build scripts, and the compiler would have its own back channel for changing
321
351
the linkage of the C library along the lines of ` #[link(.., cfg(..))] ` above.
322
352
353
+ * Another approach has [ been proposed recently] [ rfc-1684 ] that has
354
+ rustc define an environment variable to specify the C runtime kind.
355
+
356
+ [ rfc-1684 ] : https://github.com/rust-lang/rfcs/pull/1684
357
+
358
+ * Instead of extending the semantics of ` -C target-feature ` beyond "CPU
359
+ features", we could instead add a new flag for the purpose, e.g. `-C
360
+ custom-feature`.
361
+
323
362
# Unresolved questions
324
363
[ unresolved ] : #unresolved-questions
325
364
0 commit comments