-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rustc-book: Document -C target-feature=+crt-static
#71586
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -402,12 +402,35 @@ machine. Each target has a default base CPU. | |
|
||
## target-feature | ||
|
||
Individual targets will support different features; this flag lets you control | ||
enabling or disabling a feature. Each feature should be prefixed with a `+` to | ||
enable it or `-` to disable it. Separate multiple features with commas. | ||
This option controls either CPU instruction set extensions that can be used during code generation, | ||
or static linking. | ||
|
||
To see the valid options and an example of use, run `rustc --print | ||
target-features`. | ||
In both cases `-C target-feature=+x` enables feature `x` and `-C target-feature=-x` disables it. | ||
|
||
Multiple features can be specified by separating them with commas - `-C target-feature=+x,-y`. | ||
|
||
For each supported feature `x` `target_feature = "x"` becomes a `cfg` predicate usable early during | ||
compilation. | ||
Code configured with `cfg(target_feature = "x")` is kept if the feature `x` is enabled, | ||
and removed otherwise. | ||
|
||
If the enabled feature is not supported for the current target, the behavior is unspecified. | ||
<!-- There are multiple bugs here | ||
- Unknown CPU features go straight to LLVM and appear as LLVM warnings. | ||
- At configure time `crt-static` predicate is set even if the target doesn't support `crt-static`. | ||
- At link time `crt-static` is sometimes ignored | ||
if the target doesn't support it and sometimes not. | ||
--> | ||
|
||
To see the valid features and an example of use, run `rustc --print target-features`. | ||
|
||
#### CPU instruction set extensions | ||
|
||
Target features for CPU instruction set extensions can enable or disable | ||
architecture-dependent CPU features, like `+neon` or `-sse`. | ||
|
||
Each target and [`target-cpu`](#target-cpu) has a default set of enabled | ||
features. | ||
|
||
Using this flag is unsafe and might result in [undefined runtime | ||
behavior](../targets/known-issues.md). | ||
|
@@ -416,11 +439,53 @@ See also the [`target_feature` | |
attribute](../../reference/attributes/codegen.md#the-target_feature-attribute) | ||
for controlling features per-function. | ||
|
||
This also supports the feature `+crt-static` and `-crt-static` to control | ||
[static C runtime linkage](../../reference/linkage.html#static-and-dynamic-c-runtimes). | ||
#### Static linking | ||
|
||
Each target and [`target-cpu`](#target-cpu) has a default set of enabled | ||
features. | ||
Target feature `crt-static` can be used to enable or disable static linking, | ||
with the default depending on the current target. | ||
`-C target-feature=+crt-static` is similar to `-static` in other compilers, | ||
standard C library in particular is linked statically in this case. | ||
|
||
The exact meaning of `+crt-static` depends heavily | ||
on the current target and the produced crate type. | ||
|
||
- ELF-based executables. | ||
If the target supports statically linked executables, | ||
then the linker will be instructed (`-static`) to produce one. | ||
The executable will be self-contained, | ||
will contain code from all the used libraries, including `libc`, inside it, | ||
and will be able to run without a dynamic loader (no `INTERP` header). | ||
|
||
If the target doesn't support both position-independent and statically linked executables, | ||
then `-C target-feature=+crt-static` "wins" over `-C relocation-model=pic`, | ||
and the linker is instructed (`-static`) to produce a statically linked | ||
but not position-independent executable. | ||
|
||
- ELF-based shared libraries. | ||
If the target supports statically linked shared libraries, | ||
then the linker will be instructed (`-shared -static`) to produce one. | ||
The shared library will contain code from all the used libraries, including `libc`, inside it. | ||
This option is not widely supported or used. | ||
|
||
- PE-based executables (Windows). | ||
The produced executable will contain code from all the user-level libraries, including | ||
[C Run-Time Libraries (CRT)](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What user-level libraries will it statically link to other than the CRT? For There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Rust crates. If after that anything is still linked dynamically, then we get into the
Good catch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To me |
||
but may still link dynamically to system libraries like `kernel32.dll`. | ||
|
||
- PE-based shared libraries (Windows). | ||
The produced shared library will contain code from all the user-level libraries, including | ||
[C Run-Time Libraries (CRT)](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features), | ||
but may still link dynamically to system libraries like `kernel32.dll`. | ||
|
||
*WARNING!* If some libraries (native or Rust crates) in the dependency tree exist only in the | ||
dynamic variant they may be linked dynamically breaking the self-contained-ness property, | ||
re-adding the `INTERP` header for ELF executables, and possibly working incorrectly due to mismatch | ||
between dynamically linked libraries and injected startup objects specific to static linking. | ||
A request to turn this case into an error is tracked in | ||
[issue #39998](https://github.com/rust-lang/rust/issues/39998). | ||
|
||
An alternative description of this feature can be found in the | ||
[reference](../../reference/linkage.html#static-and-dynamic-c-runtimes). | ||
|
||
## bitcode-in-rlib | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I strongly suspect that #69519 was a hack rather than a proper solution, but I need some time to prepare a musl setup and verify things. (Proc-macros shouldn't be any different to cdylibs and dylibs with regards to linking behavior.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was the problem 😉
TL;DR It's a hack.
Musl target is a "weirdo". Because of the legacy decisions it defaults to static linking so it cannot produce dylibs, cdylibs and proc-macros. Now lack of proc-macro support doesn't matter when cross-compiling from the host which supports them to musl.
It becomes difficult when using musl as the host toolchain. Since it defaults to static linking proc-macros don't work. To build them one had to use
target-feature=-crt-static
and lose ability to statically link binaries.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mati865
First, musl toolchain actually supports statically linking self-contained
.so
s, despite the flag inrustc
target spec saying otherwise, I tried it (at least with "hello world"-like examples).Second, that doesn't mean that we want to use it for proc macros (as well as cdylibs and dylibs) at the same time as we are building a statically linked executable.
So, one common
RUSTFLAGS="-Ctarget-feature=+crt-static"
(or a target spec default) in this case brings collateral damage on the crates which it is not supposed to apply to.I see multiple possible solutions here some of which could be more principled than what #69519 did.
-Ctarget-feature=-crt-static
for proc macro crates or all libraries in Cargo, modifying RUSTFLAGS. Question: how to opt-out?-Ctarget-feature=+crt-static-dylib
controlling static linking of libraries instead of-Ctarget-feature=-crt-static
. It would almost never be used on Linux (not sure about windows-msvc and wasm).crt-static
, but introduce a new option-C disable-crt-static-for-dylibs
or something. Cargo would then use it for proc macro crates or all libraries. Question: how to opt-out?+crt-static
for dylibs if the target doesn't support it. This is fragile, musl actually supports it despite the current value of the flag of the musl target spec. If the flag is enabled, proc macros will break.+crt-static
for dylibs always. They are almost never used on Linux (not sure about windows-msvc and wasm).+crt-static-dylib
looks strictly better.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crt-static
defaults in target specs - one for executables and one for libraries. Solves one half of the problem, but explicit+crt-static
in RUSTFLAGS will still cause collateral damage.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll turn this into a proper issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#71651