authorbors <bors@rust-lang.org> 2025-07-08 22:24:06 UTC
committerbors <bors@rust-lang.org> 2025-07-08 22:24:06 UTC
log34097a38afc9efdedf776d3f1c84a190ff334886
treea40ec52854c9e730651b748a28cd7f342285f6ae
parentab68b0fb26485ab1fa6977b2d8b59cc8a171c4aa
parent5059315e28fde405edffd7ad9eed3853cc412fad

Auto merge of #140525 - lqd:stabilize-lld, r=petrochenkov

Use lld by default on `x86_64-unknown-linux-gnu` stable This PR and stabilization report is joint work with `@Kobzol.` #### Use LLD on `x86_64-unknown-linux-gnu` by default, and stabilize `-Clinker-features=-lld` and `-Clink-self-contained=-linker` This PR proposes making LLD the default linker on the `x86_64-unknown-linux-gnu` target for the artifacts we distribute, and also stabilizing the `-Clinker-features=-lld` and `-Clink-self-contained=-linker` codegen options to make it possible to opt out. LLD has been used as the default linker on nightly and CI on this target since May 2024 ([PR](https://github.com/rust-lang/rust/pull/124129), [blog post](https://blog.rust-lang.org/2024/05/17/enabling-rust-lld-on-linux.html)), and it seems like it is working fine, so we would like to propose stabilizing it. The main motivation for using LLD instead of the default BFD linker is improving [compilation times](https://perf.rust-lang.org/compare.html?start=b3e117044c7f707293edc040edb93e7ec5f7040a&end=baed03c51a68376c1789cc373581eea0daf89967&stat=instructions%3Au&tab=compile). For example, in the linked benchmark, it makes incremental recompilation of `ripgrep` in `debug` more than twice faster. Another benefit is that Rust compilation becomes more consistent and self-contained, because we will use a known version of the LLD linker, rather than "whatever GNU ld version is on the user's system". Due to the performance benefit being so huge, many people already opt into using LLD (or other fast linkers, such as mold) using various approaches ([1](https://github.com/search?type=code&q=%2Flinker-flavor%5B%3D+%5Dgnu-lld-cc%2F), [2](https://github.com/search?type=code&q=%2Flinker-features%5B%3D+%5D%5C%2Blld%2F), [3](https://github.com/search?type=code&q=language%3Atoml+%22-fuse-ld%3Dlld%22), [4](https://github.com/search?type=code&q=language%3Arust+%22-fuse-ld%3Dlld%22)). By making LLD the default linker on the `x86_64-unknown-linux-gnu` target, we will be able to speed up Rust compilation out of the box, without users having to opt in or know about it. > You can find an extended version of this stabilization report which includes analysis of crater results and more data [here](https://hackmd.io/tFDifkUcSLGoHPBRIl0z8w?view). ## What is being stabilized - `rust-lld` being used as the default linker on the `x86_64-unknown-linux-gnu` target. - Note that `rust-lld` is being enabled by default in the compiler artifacts distributed by our CI/rustup. It is still possible to use the system linker by default using `rust.lld = false` in `bootstrap.toml`, which can be useful e.g. for some Linux distros that might not want to use the LLD we distribute. - This is done by activating the LLD linker feature and using the self-contained linker on that target. Both of which are also usable on the CLI, if some opt outs are necessary, as described below. - `-Clinker-features=-lld` on the `x86_64-unknown-linux-gnu` target. This codegen option tells rustc to disable using the LLD linker. - Note that other options for this codegen flag (`cc`) remain unstable. - Note that only the opt-out is being stabilized, and only for `x86_64-unknown-linux-gnu`: opting in, or using the flag on other targets would still need to pass `-Zunstable-options`. - This flag is being stabilized so that users can opt out of LLD on stable, which would it turn also opt out of using the self-contained linker (since it's an LLD). - `-Clink-self-contained=-linker`. This codegen option tells rustc to use the self-contained linker. It's not particularly useful to turn it on by itself, but when enabled and combined with `-Clinker-features=+lld`, rustc will use the `rust-lld` linker wrapper shipped with the compiler toolchain, instead of some `lld` binary that the linker driver will find in the `PATH`. - Note that other options for this codegen flag (other than the previously stable `y/yes/n/no`). - Note that only the opt-out is being stabilized, and only for `x86_64-unknown-linux-gnu`: opting in, or using this flag on other targets would still need to pass `-Zunstable-options`. - This flag is being stabilized so that users can opt out of using self-contained linking on stable. Doing this would then fall back to using the system `lld`. To opt out of using LLD, `RUSTFLAGS="-Clinker-features=-lld"` would be used. To opt out of using `rust-lld`, falling back to the LLD installed on the system, `RUSTFLAGS="-Clink-self-contained=-linker"` would be used. ## Tests When enabling `rust-lld` on nightly, we also switched x64 linux to use it at stage >= 1, meaning that all tests have been running with lld since May 2024, on CI as well as contributors' machines. (Post opt-dist tests also had been using it when running their test subset earlier than that). There are also a few tests dedicated to the CLI behavior, or ensuring the default linker is indeed the one we expect: - [link-self-contained-consistency](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/ui/linking/link-self-contained-consistency.rs): Checks that `-Clink-self-contained` options are not inconsistent (i.e. that passing both `+linker` and `-linker` is an error). - [link-self-contained-unstable](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/ui/linking/link-self-contained-unstable.rs): Checks that only the `-linker` and `y/yes/n/no` options for `-Clink-self-contained` are stable. - [linker-features-unstable-cc](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/ui/linking/linker-features-unstable-cc.rs): Checks that only the non-lld options of `-Clinker-features` are unstable. - [linker-features-lld-disallowed](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/ui/linking/linker-features-lld-disallowed.rs): Checks that `-Clinker-features=-lld` is only stable on `x86_64-unknown-linux-gnu`. - [link-self-contained-linker-disallowed](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/ui/linking/link-self-contained-linker-disallowed.rs): Checks that `-Clink-self-contained=-linker` is only stable on `x86_64-unknown-linux-gnu`. - [no-gc-encapsulation-symbols](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/ui/linking/no-gc-encapsulation-symbols.rs): Checks that that linker encapsulation symbols are not garbage collected by LLD, so that crates like [linkme](https://github.com/dtolnay/linkme) still work. - [rust-lld](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/run-make/rust-lld): Checks that LLD is actually used when enabled with `-Clinker-features=+lld` and `-Clink-self-contained=+linker`. - [rust-lld-x86_64-unknown-linux-gnu](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/run-make/rust-lld-x86_64-unknown-linux-gnu): Checks that LLD is used by default on `x86_64-unknown-linux-gnu` when the bootstrap `rust.lld` config option is `true`. - [rust-lld-x86_64-unknown-linux-gnu-dist](https://github.com/rust-lang/rust/blob/1117bc1e6ce049495b0044dfe756afafc817d2d7/tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist): Dist test that checks that our distributed `x86_64-unknown-linux-gnu` archives actually use LLD by default. ## Ecosystem impact As already stated, LLD has been used as the default linker on x64 Linux on nightly for almost a year, and we haven't seen any blockers to stabilization in that time. There were a handful of issues reported, these are discussed later below. Furthermore, two crater runs ([November 2023](https://crater-reports.s3.amazonaws.com/pr-117684-2/index.html), [February 2025](https://crater-reports.s3.amazonaws.com/pr-137044-3/index.html)), were performed to test the impact of using LLD as the default linker. A triage of the earlier crater run was previously done [here](https://hackmd.io/OAJxlxc6Te6YUot9ftYSKQ), but all the important findings from both crater runs are reported below. Below is a list of compatibility differences between BFD and LLD that we have encountered. There is a more thorough list of differences in [this post](https://maskray.me/blog/2020-12-19-lld-and-gnu-linker-incompatibilities) from the current LLD maintainer. From that post, "99.9% pieces of software work with ld.lld without a change". --- ### `.ctors/.dtors` sections [#128286](https://github.com/rust-lang/rust/issues/128286) reported an issue where LLD was unable to link certain CUDA library was using these sections that were using the `.ctors/.dtors` ELF sections. These were deprecated a long time ago (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770), replaced with a more modern `.init_array/.fini_array` sections. LLD doesn't (and won't) support these sections ([1](https://github.com/llvm/llvm-project/issues/68071), [2](https://github.com/llvm/llvm-project/issues/30572)), so if they appear in input object files, the linked artifact might produce incorrect behavior, because e.g. some global variables might not get initialized properly. However, the usage of `.ctors/.dtors` should be very rare in practice. We have performed a [crater run](https://github.com/rust-lang/rust/pull/137044) to test this. It has identified only 8 crates where the `.ctors/.dtors` section is occurring in the final linked artifact. It was caused by a few crates using the `.ctors` link section manually, and by using a very (~6 year) old version of the [ctor](https://crates.io/crates/ctor) crate. [Crater run analysis](https://hackmd.io/tFDifkUcSLGoHPBRIl0z8w?view#ctorsdtors-sections) **Possible workaround** It is possible to [detect](https://github.com/rust-lang/rust/commit/e5e2316712e19036eb40e0bf59150f25e35f9880) if `.ctors/.dtors` section is present in the final linked artifact (LLD will keep it there, but it won't be populated), and warn users about it. This check is very cheap and doesn't even appear on [perf](https://github.com/rust-lang/rust/pull/112049#issuecomment-2661125340). We have benchmarked the check on a 240 MiB Chrome binary, where it took 0.8ms with page cache flushed, and 0.06ms with page cache primed (which should be the common case, as the linked artifact is written to disk just before the check is performed). In theory, this could be also solved with a linker script that moves `.ctors` to `.init_array`. We think that these sections should be so rare that it is not worth it to implement any workarounds for now. --- ### Different garbage collection behavior [#130397](https://github.com/rust-lang/rust/issues/130397) reported an issue where LLD prunes a local symbol, so it is missing in the linked artifact. However, BFD keeps the same symbol, so it is a regression. This is caused by a difference in linker garbage collection. Rust uses `--gc-sections` and puts each function into a separate linker section, which prunes unused code. There is some code (specifically the somewhat popular [linkme](https://github.com/dtolnay/linkme) crate) that (arguably ab-)uses so called linker encapsulation symbols to achieve distributed slices. BFD (2.37+) uses a conservative linking mode that works as intended with this behavior, but it might slightly increase binary size of the linked artifact. LLD does not use this workaround by default, which causes the sections to be eliminated, but it can be made to use the conservative mode using [`-z nostart-stop-gc`](https://lld.llvm.org/ELF/start-stop-gc.html#z-start-stop-gc). To avoid this issue, we told LLD to use the [conservative mode](https://github.com/rust-lang/rust/pull/137685), which maintains backwards compatibility with BFD. We found that it has [no effect](https://github.com/rust-lang/rust/pull/112049#issuecomment-2666028775) on compilation performance and binary size in our benchmark suite. With this change, `linkme` works. Since then, rust-lang/rust#140872 removed `linkme` distributed slice's dependence on conservative GC behavior, so this PR also removes that conservative mode: no transition period is necessary, as the PR immediately fixed the crate with no source changes. [Crater run analysis](https://hackmd.io/tFDifkUcSLGoHPBRIl0z8w?view#Different-garbage-collection-behavior) --- ### Various uncommon issues A small number of issues that only occurred in a handful of instances were found in crater, and it is unclear if LLD is at fault or if there is some other issue that was not detected with BFD. You can examine these [here](https://hackmd.io/tFDifkUcSLGoHPBRIl0z8w?view#Various-uncommon-issues). --- ### Missing jobserver support LLD doesn't support the jobserver protocol for limiting the number of threads used, it simply defaults to using all available cores, and is one of the reasons why it's faster than BFD. However, this should mostly be a non-issue, because most of the linking done during high parallelism sections of `cargo build` is linking of build scripts and proc macros, which are typically very fast to link (e.g. ~50ms), and a potential oversubscription of cores thus doesn't hurt that much. When the final artifact is linked (which typically takes the most time), there should be no other sources of parallelism conflicts from compiling other code, so LLD should be able to use all available threads. That being said, it is a difference of behavior, where previously a `-j` flag was generally not using more cpu than the specified limit. It can be impactful in some resource-constrained systems, but to be clear that is already the case today due to [cargo parallelism](https://github.com/rust-lang/cargo/issues/9157). This could be one reason to opt out of using `rust-lld` on some systems. LLD has support for limiting the number of threads to use, so in theory rustc could try to get all the jobserver tokens available and use that as lld's thread limit. It'd still be suboptimal as new tokens would not be dynamically detected, and we could be using less threads than available. We did a benchmark on a real-world crate that shows that using multiple LLD threads for intermediate artifacts doesn't seem to have a performance effect. You can find it [here](https://hackmd.io/tFDifkUcSLGoHPBRIl0z8w?view#Missing-jobserver-support). --- #### Opting out of LLD in the ecosystem We have also examined repositories where people opted out of LLD on nightly, using [this GitHub query](https://github.com/search?q=%22linker-features%3D-lld%22&type=code). The summary can be found below: <details> <summary>Summary of LLD opt outs</summary> > This examination was performed on 2025-03-09. Here we briefly examine the most common reasons why people use `-Zlinker-features=-lld`, based on comments and git history. - Nix/NixOS ([1](https://github.com/rszyma/vscode-kanata/blob/59d703dff5a238b14ab3759cac27f73fb34bbcfe/flake.nix#L33), [2](https://github.com/sbernauer/breakwater/blob/3cc3449fc126c5c99d4a971733fd32be589884e0/.cargo/config.toml#L4), [3](https://github.com/tiiuae/ebpf-firewall/blame/32bdb17cedd1c9bea1ab3482623de458d95da7d0/.cargo/config.toml#L2), [4](https://github.com/jules-sommer/wavetheme-gen/blob/f5f657d014d4a30607625afb70f810c229c0294e/Cargo.toml#L4), [5](https://github.com/LayerTwo-Labs/zside-rust/blob/e4266f5c5571a1b180a9c70cf0939c7070e410c7/.cargo/config.toml#L10), [6](https://github.com/przyjacielpkp/zkml/blob/22a4aef24e9d2c77789229d7c634fc67e9eb1184/README.md?plain=1#L78), [7](https://github.com/LayerTwo-Labs/thunder-rust/blob/2222d53474c8d2d0428b4c56f8157095dced6d5a/.cargo/config.toml#L2), [8](https://github.com/enesoztrk/nixos-tc-aya-test/blob/b2ffa59d3eba8b60fd04b0a4c8bbe047400eb981/.cargo/config.toml#L4), [9](https://github.com/lowRISC/container-hotplug/blob/3ead4ef9c7f79c303392178c99677dbecff1aea6/.cargo/config.toml#L2), [10](https://github.com/Eliah-Lakhin/ad-astra/blob/ca6b8c8a5dba7bb5e894f3f1013f17876962a021/work/examples/lsp-client/src/extension.ts#L94)) - There was an [issue](https://github.com/NixOS/nixpkgs/issues/312661) with LLD, which seems to have been fixed with https://github.com/NixOS/nixpkgs/pull/314268. It's unclear whether that fixed all the Nix issues though. - Issues with linkme ([1](https://github.com/0xPolygonZero/zk_evm/blob/ef388619ffbd5305209519a3a5bc0396185d68ac/.cargo/config.toml#L4), [2](https://github.com/conjure-cp/conjure-oxide/blob/be0fc5827ff90e8486d416cc184b6ce24f73bf01/README.md?plain=1#L20), [3](https://github.com/clchiou/garage/blob/c5d8444d56bb6ee24ca95e5c6b9880ed996f4918/rust/.cargo/config.toml#L6), [4](https://github.com/PonasKovas/craftflow/blob/5b4cc1a5196e08a975368399fefda4b71f3a2f6f/.cargo/config.toml#L3), [5](https://github.com/kezhuw/zookeeper-client-rust/blob/4e27c7de2a7cc5e709af012b791c8fea9bb47f1f/.github/workflows/ci.yml#L82), [6](https://github.com/niklasdewally/conjure-oxide/blob/8fe60c12bca7011a2f9eded4b7c95ad0e77b6f44/.github/workflows/code-coverage.yml#L48), [7](https://github.com/kezhuw/spawns/blob/c8b468379805de9df3287c01b94b4ed3db6b61ed/.github/workflows/ci.yml#L74)) - These should be resolved with the conservative garbage collection ([#137685](https://github.com/rust-lang/rust/pull/137685)). - Bazel ([1](https://github.com/google-parfait/confidential-federated-compute/blob/1823f69ed8f5f4f819f7bfa21da1ca629fdc826b/.bazelrc#L71)), WASM ([1](https://github.com/Eliah-Lakhin/ad-astra/blob/ca6b8c8a5dba7bb5e894f3f1013f17876962a021/work/examples/wasm-build.sh#L37), [2](https://github.com/yacineb/pgrx-wasi-test/blob/2bf99037ca1b650b2cbc35f1257a87fb6ead0920/build.sh#L21)), uncategorized ([2](https://github.com/nbdd0121/r2vm/blob/5118be6b9e757c6fef2f019385873f403c23c548/.cargo/config.toml#L3), [3](https://github.com/Wyvern/Img/blame/45020c7e1dc4926c8129647014c708db0c13f463/.cargo/config.toml#L209), [4](https://github.com/arnaudpoullet/leptos-i18n-compile-error/blob/042eb835f7ca0dc36be67cf7fe65b35b22b6059f/README.md?plain=1#L89), [5](https://github.com/JonLeeCon/numerical-rust-cpu/blob/fd0b3006768ed81c56147044dc05c92b11b7b6f0/exercises/.cargo/config.toml#L13), [6](https://github.com/PonasKovas/shallowclone/blob/be65f2ec923cac6ceedbc8db520c89969ebfce7c/.github/workflows/rust.yml#L20)) - Reason unclear. </details> ## History The idea to use a faster linker by default has been on the radar for quite some time ([#39915](https://github.com/rust-lang/rust/issues/39915), [#71515](https://github.com/rust-lang/rust/issues/71515)). There were [very early attempts](https://github.com/rust-lang/rust/pull/29974) to use the gold linker by default, but these had to be [reverted](https://github.com/rust-lang/rust/pull/30913) because of compatibility issues. Support for LLD was implemented back in [2017](https://github.com/rust-lang/rust/pull/40018), but it has not been made default yet, except for some more niche targets, such as [WASM](https://github.com/rust-lang/rust/pull/48125), [ARM Cortex](https://github.com/rust-lang/rust/pull/53648) or [RISC-V](https://github.com/rust-lang/rust/pull/53822). It took quite some time to figure out how should the interface for selecting the linker (and the way it is invoked) look like, as it differs a lot between different platforms, linkers and compiler drivers. During that time, LLD has matured and achieved [almost perfect compatibility](https://maskray.me/blog/2020-12-19-lld-and-gnu-linker-incompatibilities) with the default Linux linker (BFD). - [#56351](https://github.com/rust-lang/rust/pull/56351) stabilized `-Clinker-flavor`, which is used to determine how to invoke the linker. It is especially useful on targets where selecting the linker directly with `-Clinker` is not possible or is impractical. - December 2018, author `@davidtwco,` reviewer `@nagisa` - [#76158](https://github.com/rust-lang/rust/pull/76158) stabilized `-Clink-self-contained=[y|n]`, which allows overriding the compiler's heuristic for deciding whether it should use self-contained or external tools (linker, sanitizers, libc, etc.). It only allowed using the self-contained mode either for everything (`y`) or nothing (`n`), but did not allow granular choice. - September 2020, author `@mati864,` reviewer `@petrochenkov` - [#85961](https://github.com/rust-lang/rust/pull/85961) implemented the `-Zgcc-ld` flag, which was a hacky way of opting into LLD usage. - June 2021, author `@sledgehammervampire,` reviewer `@petrochenkov` - [MCP 510](https://github.com/rust-lang/compiler-team/issues/510) proposed stabilizing the behavior of `-Zgcc-ld` using more granular flags (`-Clink-self-contained=linker -Clinker-flavor=gcc-lld`). - Initially implemented in [#96827](https://github.com/rust-lang/rust/pull/96827), but `@petrochenkov` [suggested](https://github.com/rust-lang/rust/pull/96827#issuecomment-1208441595) a slightly different approach. - The PR was split into [#96884](https://github.com/rust-lang/rust/pull/96884), where it was decided what will be the individual components of `-Clink-self-contained=linker`. - And [#96401](https://github.com/rust-lang/rust/pull/96401), which implemented the `-Clinker-flavor` part. - The MCP was finally implemented in [#112910](https://github.com/rust-lang/rust/pull/112910). - [#116514](https://github.com/rust-lang/rust/pull/116514) then removed `-Zgcc-ld`, as it was replaced by `-Clinker-flavor=gnu-lld-cc` + `-Clink-self-contained=linker`. - April 2022 - October 2023, author `@lqd,` reviewer `@petrochenkov` - Various linker handling refactorings were performed in the meantime: [#97375](https://github.com/rust-lang/rust/pull/97375), [#98212](https://github.com/rust-lang/rust/pull/98212), [#100126](https://github.com/rust-lang/rust/pull/100126), [#100552](https://github.com/rust-lang/rust/pull/100552), [#102836](https://github.com/rust-lang/rust/pull/102836), [#110807](https://github.com/rust-lang/rust/pull/110807), [#101988](https://github.com/rust-lang/rust/pull/101988), [#116515](https://github.com/rust-lang/rust/pull/116515) - The implementation of linker flavors with LLD was causing a sort of a combinatorial explosion of various options. [#119906](https://github.com/rust-lang/rust/pull/119906) suggested a different approach for linker flavors (described [here](https://github.com/rust-lang/rust/pull/119906#issuecomment-1894088306)), where the individual flavors could be enabled separately using `+/-` (e.g. `+lld`). - After some back and forth, this idea was moved to `-Clinker-features` (see [comment 1](https://github.com/rust-lang/rust/pull/119906#issuecomment-1895693162) and [comment 2](https://github.com/rust-lang/rust/pull/119906#issuecomment-1980801438)), which was implemented in [#123656](https://github.com/rust-lang/rust/pull/123656). - April 2024, author `@lqd,` reviewer `@petrochenkov` - [#124129](https://github.com/rust-lang/rust/pull/124129) enabled LLD by default on nightly. - April 2024, author `@lqd,` reviewer `@petrochenkov` - [#137685](https://github.com/rust-lang/rust/pull/137685), [#137926](https://github.com/rust-lang/rust/pull/137926) enabled the conservative gargage collection mode (`-znostart-stop-gc`) to improve compatibility with BFD. - February 2025, author `@lqd,` reviewer `@petrochenkov` (implementation), author `@kobzol,` reviewer `@lqd` (test) - [#96025](https://github.com/rust-lang/rust/pull/96025) (April 2022), [#117684](https://github.com/rust-lang/rust/pull/117684) (November 2023), [#137044](https://github.com/rust-lang/rust/pull/137044) (February 2025): crater runs. ## Unresolved questions/concerns - Is changing the linker considered a breaking change? In (hopefully very rare) cases, it might break some existing code. It should mostly only affect the final linked artifact, so it should be easy to opt out. - Similarly, is the single-threaded behavior of such tools encompassed in our stability guarantee: it can be observed via the `-j` job limit (though I believe we have/had some open issues on sometimes using more CPU resources than the job count limit implied). As mentioned above, LLD does not support the jobserver protocol. - A concern [was raised](https://github.com/rust-lang/rust/issues/71515#issuecomment-2612370229) about increased memory usage of LLD. We should probably let users know about the possibly increased memory usage, and jobserver incompatibility: we did so when announcing this landing on nightly. - LLD seems to produce [slightly larger](https://perf.rust-lang.org/compare.html?start=b3e117044c7f707293edc040edb93e7ec5f7040a&end=baed03c51a68376c1789cc373581eea0daf89967&stat=size%3Alinked_artifact&tab=compile) binary artifacts. This can be partially clawed back using Identical Code Folding (`-Clink-args=-Wl,--icf=all`). - Should we detect the outdated `.ctors/.dtors` sections to provide a better error message, even if that should be rare in practice? --- ### Next steps After the FCP completes: - we should land this PR at the beginning of a beta cycle, to maximize time for testing - keep an eye on the beta crater run results for possible linker issues (or do a dedicated beta crater run with only this change) - release a blog post announcing the change, and asking for testing feedback of the appropriate beta - depending on feedback, or if a period of testing of 6 weeks is not long enough, we could keep this change on beta for another cycle --- Development, testing, try builds were done in https://github.com/rust-lang/rust/pull/138645. r? `@petrochenkov` `@rustbot` label +needs-fcp +T-compiler

50 files changed, 369 insertions(+), 192 deletions(-)

compiler/rustc_codegen_ssa/src/back/link.rs+1-30
......@@ -1379,7 +1379,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
13791379 }
13801380 }
13811381
1382 let features = sess.opts.unstable_opts.linker_features;
1382 let features = sess.opts.cg.linker_features;
13831383
13841384 // linker and linker flavor specified via command line have precedence over what the target
13851385 // specification specifies
......@@ -3327,35 +3327,6 @@ fn add_lld_args(
33273327 // this, `wasm-component-ld`, which is overridden if this option is passed.
33283328 if !sess.target.is_like_wasm {
33293329 cmd.cc_arg("-fuse-ld=lld");
3330
3331 // On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some
3332 // section garbage-collection features. For example, the somewhat popular `linkme` crate and
3333 // its dependents rely in practice on this difference: when using lld, they need `-z
3334 // nostart-stop-gc` to prevent encapsulation symbols and sections from being
3335 // garbage-collected.
3336 //
3337 // More information about all this can be found in:
3338 // - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order
3339 // - https://lld.llvm.org/ELF/start-stop-gc
3340 //
3341 // So when using lld, we restore, for now, the traditional behavior to help migration, but
3342 // will remove it in the future.
3343 // Since this only disables an optimization, it shouldn't create issues, but is in theory
3344 // slightly suboptimal. However, it:
3345 // - doesn't have any visible impact on our benchmarks
3346 // - reduces the need to disable lld for the crates that depend on this
3347 //
3348 // Note that lld can detect some cases where this difference is relied on, and emits a
3349 // dedicated error to add this link arg. We could make use of this error to emit an FCW. As
3350 // of writing this, we don't do it, because lld is already enabled by default on nightly
3351 // without this mitigation: no working project would see the FCW, so we do this to help
3352 // stabilization.
3353 //
3354 // FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the
3355 // future.
3356 if sess.target.llvm_target == "x86_64-unknown-linux-gnu" {
3357 cmd.link_arg("-znostart-stop-gc");
3358 }
33593330 }
33603331
33613332 if !flavor.is_gnu() {
compiler/rustc_session/src/config.rs+77-22
......@@ -370,12 +370,34 @@ impl LinkSelfContained {
370370 }
371371
372372 /// To help checking CLI usage while some of the values are unstable: returns whether one of the
373 /// components was set individually. This would also require the `-Zunstable-options` flag, to
374 /// be allowed.
375 fn are_unstable_variants_set(&self) -> bool {
376 let any_component_set =
377 !self.enabled_components.is_empty() || !self.disabled_components.is_empty();
378 self.explicitly_set.is_none() && any_component_set
373 /// unstable components was set individually, for the given `TargetTuple`. This would also
374 /// require the `-Zunstable-options` flag, to be allowed.
375 fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
376 if self.explicitly_set.is_some() {
377 return Ok(());
378 }
379
380 // `-C link-self-contained=-linker` is only stable on x64 linux.
381 let has_minus_linker = self.disabled_components.is_linker_enabled();
382 if has_minus_linker && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
383 return Err(format!(
384 "`-C link-self-contained=-linker` is unstable on the `{target_tuple}` \
385 target. The `-Z unstable-options` flag must also be passed to use it on this target",
386 ));
387 }
388
389 // Any `+linker` or other component used is unstable, and that's an error.
390 let unstable_enabled = self.enabled_components;
391 let unstable_disabled = self.disabled_components - LinkSelfContainedComponents::LINKER;
392 if !unstable_enabled.union(unstable_disabled).is_empty() {
393 return Err(String::from(
394 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` \
395 are stable, the `-Z unstable-options` flag must also be passed to use \
396 the unstable values",
397 ));
398 }
399
400 Ok(())
379401 }
380402
381403 /// Returns whether the self-contained linker component was enabled on the CLI, using the
......@@ -402,7 +424,7 @@ impl LinkSelfContained {
402424 }
403425}
404426
405/// The different values that `-Z linker-features` can take on the CLI: a list of individually
427/// The different values that `-C linker-features` can take on the CLI: a list of individually
406428/// enabled or disabled features used during linking.
407429///
408430/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be
......@@ -442,6 +464,39 @@ impl LinkerFeaturesCli {
442464 _ => None,
443465 }
444466 }
467
468 /// When *not* using `-Z unstable-options` on the CLI, ensure only stable linker features are
469 /// used, for the given `TargetTuple`. Returns `Ok` if no unstable variants are used.
470 /// The caller should ensure that e.g. `nightly_options::is_unstable_enabled()`
471 /// returns false.
472 pub(crate) fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
473 // `-C linker-features=-lld` is only stable on x64 linux.
474 let has_minus_lld = self.disabled.is_lld_enabled();
475 if has_minus_lld && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
476 return Err(format!(
477 "`-C linker-features=-lld` is unstable on the `{target_tuple}` \
478 target. The `-Z unstable-options` flag must also be passed to use it on this target",
479 ));
480 }
481
482 // Any `+lld` or non-lld feature used is unstable, and that's an error.
483 let unstable_enabled = self.enabled;
484 let unstable_disabled = self.disabled - LinkerFeatures::LLD;
485 if !unstable_enabled.union(unstable_disabled).is_empty() {
486 let unstable_features: Vec<_> = unstable_enabled
487 .iter()
488 .map(|f| format!("+{}", f.as_str().unwrap()))
489 .chain(unstable_disabled.iter().map(|f| format!("-{}", f.as_str().unwrap())))
490 .collect();
491 return Err(format!(
492 "`-C linker-features={}` is unstable, and also requires the \
493 `-Z unstable-options` flag to be used",
494 unstable_features.join(","),
495 ));
496 }
497
498 Ok(())
499 }
445500}
446501
447502/// Used with `-Z assert-incr-state`.
......@@ -2638,26 +2693,21 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26382693 }
26392694 }
26402695
2641 if !nightly_options::is_unstable_enabled(matches)
2642 && cg.force_frame_pointers == FramePointer::NonLeaf
2643 {
2696 let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
2697 if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
26442698 early_dcx.early_fatal(
26452699 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
26462700 and a nightly compiler",
26472701 )
26482702 }
26492703
2650 // For testing purposes, until we have more feedback about these options: ensure `-Z
2651 // unstable-options` is required when using the unstable `-C link-self-contained` and `-C
2652 // linker-flavor` options.
2653 if !nightly_options::is_unstable_enabled(matches) {
2654 let uses_unstable_self_contained_option =
2655 cg.link_self_contained.are_unstable_variants_set();
2656 if uses_unstable_self_contained_option {
2657 early_dcx.early_fatal(
2658 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
2659 the `-Z unstable-options` flag must also be passed to use the unstable values",
2660 );
2704 let target_triple = parse_target_triple(early_dcx, matches);
2705
2706 // Ensure `-Z unstable-options` is required when using the unstable `-C link-self-contained` and
2707 // `-C linker-flavor` options.
2708 if !unstable_options_enabled {
2709 if let Err(error) = cg.link_self_contained.check_unstable_variants(&target_triple) {
2710 early_dcx.early_fatal(error);
26612711 }
26622712
26632713 if let Some(flavor) = cg.linker_flavor {
......@@ -2697,7 +2747,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26972747
26982748 let cg = cg;
26992749
2700 let target_triple = parse_target_triple(early_dcx, matches);
27012750 let opt_level = parse_opt_level(early_dcx, matches, &cg);
27022751 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
27032752 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
......@@ -2706,6 +2755,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
27062755 let debuginfo = select_debuginfo(matches, &cg);
27072756 let debuginfo_compression = unstable_opts.debuginfo_compression;
27082757
2758 if !unstable_options_enabled {
2759 if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) {
2760 early_dcx.early_fatal(error);
2761 }
2762 }
2763
27092764 let crate_name = matches.opt_str("crate-name");
27102765 let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
27112766 // Parse any `-l` flags, which link to native libraries.
compiler/rustc_session/src/options.rs+2-2
......@@ -2015,6 +2015,8 @@ options! {
20152015 on a C toolchain or linker installed in the system"),
20162016 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
20172017 "system linker to link outputs with"),
2018 linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
2019 "a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
20182020 linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
20192021 "linker flavor"),
20202022 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
......@@ -2307,8 +2309,6 @@ options! {
23072309 "link native libraries in the linker invocation (default: yes)"),
23082310 link_only: bool = (false, parse_bool, [TRACKED],
23092311 "link the `.rlink` file generated by `-Z no-link` (default: no)"),
2310 linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
2311 "a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
23122312 lint_llvm_ir: bool = (false, parse_bool, [TRACKED],
23132313 "lint LLVM IR (default: no)"),
23142314 lint_mir: bool = (false, parse_bool, [UNTRACKED],
compiler/rustc_target/src/spec/mod.rs+13-2
......@@ -725,7 +725,7 @@ impl ToJson for LinkSelfContainedComponents {
725725}
726726
727727bitflags::bitflags! {
728 /// The `-Z linker-features` components that can individually be enabled or disabled.
728 /// The `-C linker-features` components that can individually be enabled or disabled.
729729 ///
730730 /// They are feature flags intended to be a more flexible mechanism than linker flavors, and
731731 /// also to prevent a combinatorial explosion of flavors whenever a new linker feature is
......@@ -756,7 +756,7 @@ bitflags::bitflags! {
756756rustc_data_structures::external_bitflags_debug! { LinkerFeatures }
757757
758758impl LinkerFeatures {
759 /// Parses a single `-Z linker-features` well-known feature, not a set of flags.
759 /// Parses a single `-C linker-features` well-known feature, not a set of flags.
760760 pub fn from_str(s: &str) -> Option<LinkerFeatures> {
761761 Some(match s {
762762 "cc" => LinkerFeatures::CC,
......@@ -765,6 +765,17 @@ impl LinkerFeatures {
765765 })
766766 }
767767
768 /// Return the linker feature name, as would be passed on the CLI.
769 ///
770 /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
771 pub fn as_str(self) -> Option<&'static str> {
772 Some(match self {
773 LinkerFeatures::CC => "cc",
774 LinkerFeatures::LLD => "lld",
775 _ => return None,
776 })
777 }
778
768779 /// Returns whether the `lld` linker feature is enabled.
769780 pub fn is_lld_enabled(self) -> bool {
770781 self.contains(LinkerFeatures::LLD)
src/bootstrap/src/core/build_steps/compile.rs+1-3
......@@ -1369,9 +1369,7 @@ pub fn rustc_cargo_env(
13691369 }
13701370
13711371 // Enable rustc's env var for `rust-lld` when requested.
1372 if builder.config.lld_enabled
1373 && (builder.config.channel == "dev" || builder.config.channel == "nightly")
1374 {
1372 if builder.config.lld_enabled {
13751373 cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1");
13761374 }
13771375
src/bootstrap/src/core/build_steps/test.rs+16-4
......@@ -262,7 +262,13 @@ impl Step for Cargotest {
262262 .args(builder.config.test_args())
263263 .env("RUSTC", builder.rustc(compiler))
264264 .env("RUSTDOC", builder.rustdoc(compiler));
265 add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No);
265 add_rustdoc_cargo_linker_args(
266 &mut cmd,
267 builder,
268 compiler.host,
269 LldThreads::No,
270 compiler.stage,
271 );
266272 cmd.delay_failure().run(builder);
267273 }
268274}
......@@ -857,7 +863,7 @@ impl Step for RustdocTheme {
857863 .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
858864 .env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
859865 .env("RUSTC_BOOTSTRAP", "1");
860 cmd.args(linker_args(builder, self.compiler.host, LldThreads::No));
866 cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage));
861867
862868 cmd.delay_failure().run(builder);
863869 }
......@@ -1033,7 +1039,13 @@ impl Step for RustdocGUI {
10331039 cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
10341040 .env("RUSTC", builder.rustc(self.compiler));
10351041
1036 add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No);
1042 add_rustdoc_cargo_linker_args(
1043 &mut cmd,
1044 builder,
1045 self.compiler.host,
1046 LldThreads::No,
1047 self.compiler.stage,
1048 );
10371049
10381050 for path in &builder.paths {
10391051 if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
......@@ -1812,7 +1824,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
18121824 }
18131825
18141826 let mut hostflags = flags.clone();
1815 hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No));
1827 hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No, compiler.stage));
18161828
18171829 let mut targetflags = flags;
18181830
src/bootstrap/src/core/builder/cargo.rs+10-5
......@@ -115,7 +115,7 @@ impl Cargo {
115115 // No need to configure the target linker for these command types.
116116 Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {}
117117 _ => {
118 cargo.configure_linker(builder);
118 cargo.configure_linker(builder, mode);
119119 }
120120 }
121121
......@@ -209,7 +209,7 @@ impl Cargo {
209209
210210 // FIXME(onur-ozkan): Add coverage to make sure modifications to this function
211211 // doesn't cause cache invalidations (e.g., #130108).
212 fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
212 fn configure_linker(&mut self, builder: &Builder<'_>, mode: Mode) -> &mut Cargo {
213213 let target = self.target;
214214 let compiler = self.compiler;
215215
......@@ -264,7 +264,12 @@ impl Cargo {
264264 }
265265 }
266266
267 for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
267 // We use the snapshot compiler when building host code (build scripts/proc macros) of
268 // `Mode::Std` tools, so we need to determine the current stage here to pass the proper
269 // linker args (e.g. -C vs -Z).
270 // This should stay synchronized with the [cargo] function.
271 let host_stage = if mode == Mode::Std { 0 } else { compiler.stage };
272 for arg in linker_args(builder, compiler.host, LldThreads::Yes, host_stage) {
268273 self.hostflags.arg(&arg);
269274 }
270275
......@@ -274,10 +279,10 @@ impl Cargo {
274279 }
275280 // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
276281 // `linker_args` here.
277 for flag in linker_flags(builder, target, LldThreads::Yes) {
282 for flag in linker_flags(builder, target, LldThreads::Yes, compiler.stage) {
278283 self.rustflags.arg(&flag);
279284 }
280 for arg in linker_args(builder, target, LldThreads::Yes) {
285 for arg in linker_args(builder, target, LldThreads::Yes, compiler.stage) {
281286 self.rustdocflags.arg(&arg);
282287 }
283288
src/bootstrap/src/core/builder/mod.rs+1-1
......@@ -1599,7 +1599,7 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
15991599 cmd.arg("-Dwarnings");
16001600 }
16011601 cmd.arg("-Znormalize-docs");
1602 cmd.args(linker_args(self, compiler.host, LldThreads::Yes));
1602 cmd.args(linker_args(self, compiler.host, LldThreads::Yes, compiler.stage));
16031603 cmd
16041604 }
16051605
src/bootstrap/src/core/config/toml/rust.rs+1-4
......@@ -619,7 +619,6 @@ impl Config {
619619 // build our internal lld and use it as the default linker, by setting the `rust.lld` config
620620 // to true by default:
621621 // - on the `x86_64-unknown-linux-gnu` target
622 // - on the `dev` and `nightly` channels
623622 // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
624623 // we're also able to build the corresponding lld
625624 // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
......@@ -628,9 +627,7 @@ impl Config {
628627 // thus, disabled
629628 // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
630629 // when the config sets `rust.lld = false`
631 if self.host_target.triple == "x86_64-unknown-linux-gnu"
632 && self.hosts == [self.host_target]
633 && (self.channel == "dev" || self.channel == "nightly")
630 if self.host_target.triple == "x86_64-unknown-linux-gnu" && self.hosts == [self.host_target]
634631 {
635632 let no_llvm_config = self
636633 .target_config
src/bootstrap/src/utils/helpers.rs+19-6
......@@ -404,8 +404,9 @@ pub fn linker_args(
404404 builder: &Builder<'_>,
405405 target: TargetSelection,
406406 lld_threads: LldThreads,
407 stage: u32,
407408) -> Vec<String> {
408 let mut args = linker_flags(builder, target, lld_threads);
409 let mut args = linker_flags(builder, target, lld_threads, stage);
409410
410411 if let Some(linker) = builder.linker(target) {
411412 args.push(format!("-Clinker={}", linker.display()));
......@@ -420,19 +421,30 @@ pub fn linker_flags(
420421 builder: &Builder<'_>,
421422 target: TargetSelection,
422423 lld_threads: LldThreads,
424 stage: u32,
423425) -> Vec<String> {
424426 let mut args = vec![];
425427 if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() {
426428 match builder.config.lld_mode {
427429 LldMode::External => {
428 args.push("-Zlinker-features=+lld".to_string());
429 // FIXME(kobzol): remove this flag once MCP510 gets stabilized
430 // cfg(bootstrap) - remove the stage 0 check after updating the bootstrap compiler:
431 // `-Clinker-features` has been stabilized.
432 if stage == 0 {
433 args.push("-Zlinker-features=+lld".to_string());
434 } else {
435 args.push("-Clinker-features=+lld".to_string());
436 }
430437 args.push("-Zunstable-options".to_string());
431438 }
432439 LldMode::SelfContained => {
433 args.push("-Zlinker-features=+lld".to_string());
440 // cfg(bootstrap) - remove the stage 0 check after updating the bootstrap compiler:
441 // `-Clinker-features` has been stabilized.
442 if stage == 0 {
443 args.push("-Zlinker-features=+lld".to_string());
444 } else {
445 args.push("-Clinker-features=+lld".to_string());
446 }
434447 args.push("-Clink-self-contained=+linker".to_string());
435 // FIXME(kobzol): remove this flag once MCP510 gets stabilized
436448 args.push("-Zunstable-options".to_string());
437449 }
438450 LldMode::Unused => unreachable!(),
......@@ -453,8 +465,9 @@ pub fn add_rustdoc_cargo_linker_args(
453465 builder: &Builder<'_>,
454466 target: TargetSelection,
455467 lld_threads: LldThreads,
468 stage: u32,
456469) {
457 let args = linker_args(builder, target, lld_threads);
470 let args = linker_args(builder, target, lld_threads, stage);
458471 let mut flags = cmd
459472 .get_envs()
460473 .find_map(|(k, v)| if k == OsStr::new("RUSTDOCFLAGS") { v } else { None })
src/doc/rustc/src/codegen-options/index.md+55-4
......@@ -235,15 +235,33 @@ coverage measurement. Its use is not recommended.
235235
236236## link-self-contained
237237
238On `windows-gnu`, `linux-musl`, and `wasi` targets, this flag controls whether the
239linker will use libraries and objects shipped with Rust instead of those in the system.
240It takes one of the following values:
238This flag controls whether the linker will use libraries and objects shipped with Rust instead of
239those in the system. It also controls which binary is used for the linker itself. This allows
240overriding cases when detection fails or the user wants to use shipped libraries.
241
242You can enable or disable the usage of any self-contained components using one of the following values:
241243
242244* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools.
243245* `y`, `yes`, `on`, `true`: use only libraries/objects shipped with Rust.
244246* `n`, `no`, `off` or `false`: rely on the user or the linker to provide non-Rust libraries/objects.
245247
246This allows overriding cases when detection fails or user wants to use shipped libraries.
248It is also possible to enable or disable specific self-contained components in a more granular way.
249You can pass a comma-separated list of self-contained components, individually enabled
250(`+component`) or disabled (`-component`).
251
252Currently, only the `linker` granular option is stabilized, and only on the `x86_64-unknown-linux-gnu` target:
253- `linker`: toggle the usage of self-contained linker binaries (linker, dlltool, and their necessary libraries)
254
255Note that only the `-linker` opt-out is stable on the `x86_64-unknown-linux-gnu` target: `+linker` is
256already the default on this target.
257
258#### Implementation notes
259
260On the `x86_64-unknown-linux-gnu` target, when using the default linker flavor (using `cc` as the
261linker driver) and linker features (to try using `lld`), `rustc` will try to use the self-contained
262linker by passing a `-B /path/to/sysroot/` link argument to the driver to find `rust-lld` in the
263sysroot. For backwards-compatibility, and to limit name and `PATH` collisions, this is done using a
264shim executable (the `lld-wrapper` tool) that forwards execution to the `rust-lld` executable itself.
247265
248266## linker
249267
......@@ -256,6 +274,39 @@ Note that on Unix-like targets (for example, `*-unknown-linux-gnu` or `*-unknown
256274the C compiler (for example `cc` or `clang`) is used as the "linker" here, serving as a linker driver.
257275It will invoke the actual linker with all the necessary flags to be able to link against the system libraries like libc.
258276
277## linker-features
278
279The `-Clinker-features` flag allows enabling or disabling specific features used during linking.
280
281These feature flags are a flexible extension mechanism that is complementary to linker flavors,
282designed to avoid the combinatorial explosion of having to create a new set of flavors for each
283linker feature we'd want to use.
284
285The flag accepts a comma-separated list of features, individually enabled (`+feature`) or disabled
286(`-feature`).
287
288Currently only one is stable, and only on the `x86_64-unknown-linux-gnu` target:
289- `lld`: to toggle trying to use the lld linker, either the system-installed binary, or the self-contained
290 `rust-lld` linker (via the [`-Clink-self-contained=+linker`](#link-self-contained) flag).
291
292For example, use:
293- `-Clinker-features=+lld` to opt into using the `lld` linker, when possible (see the Implementation notes below)
294- `-Clinker-features=-lld` to opt out instead, for targets where it is configured as the default linker
295
296Note that only the `-lld` opt-out is stable on the `x86_64-unknown-linux-gnu` target: `+lld` is
297already the default on this target.
298
299#### Implementation notes
300
301On the `x86_64-unknown-linux-gnu` target, when using the default linker flavor (using `cc` as the
302linker driver), `rustc` will try to use lld by passing a `-fuse-ld=lld` link argument to the driver.
303`rustc` will also try to detect if that _causes_ an error during linking (for example, if GCC is too
304old to understand the flag, and returns an error) and will then retry linking without this argument,
305as a fallback.
306
307If the user _also_ passes a `-Clink-arg=-fuse-ld=$value`, both will be given to the linker
308driver but the user's will be passed last, and would generally have priority over `rustc`'s.
309
259310## linker-flavor
260311
261312This flag controls the linker flavor used by `rustc`. If a linker is given with
src/doc/unstable-book/src/compiler-flags/codegen-options.md+4-4
......@@ -51,10 +51,10 @@ instead of those in the system. The stable boolean values for this flag are coar
5151- `mingw`: other MinGW libs and Windows import libs
5252
5353Out of the above self-contained linking components, `linker` is the only one currently implemented
54(beyond parsing the CLI options).
54(beyond parsing the CLI options) and stabilized.
5555
5656It refers to the LLD linker, built from the same LLVM revision used by rustc (named `rust-lld` to
5757avoid naming conflicts), that is distributed via `rustup` with the compiler (and is used by default
58for the wasm targets). One can also opt-in to use it by combining this flag with an appropriate
59linker flavor: for example, `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` will use the
60toolchain's `rust-lld` as the linker.
58for the wasm targets). One can also opt into using it by combining this flag with the appropriate
59linker feature: for example, `-Clinker-features=+lld -Clink-self-contained=+linker` will use the
60toolchain's `rust-lld` as the linker instead of the system's lld with `-Clinker-features=+lld` only.
src/doc/unstable-book/src/compiler-flags/linker-features.md deleted-35
......@@ -1,35 +0,0 @@
1# `linker-features`
2
3--------------------
4
5The `-Zlinker-features` compiler flag allows enabling or disabling specific features used during
6linking, and is intended to be stabilized under the codegen options as `-Clinker-features`.
7
8These feature flags are a flexible extension mechanism that is complementary to linker flavors,
9designed to avoid the combinatorial explosion of having to create a new set of flavors for each
10linker feature we'd want to use.
11
12For example, this design allows:
13- default feature sets for principal flavors, or for specific targets.
14- flavor-specific features: for example, clang offers automatic cross-linking with `--target`, which
15 gcc-style compilers don't support. The *flavor* is still a C/C++ compiler, and we don't want to
16 multiply the number of flavors for this use-case. Instead, we can have a single `+target` feature.
17- umbrella features: for example, if clang accumulates more features in the future than just the
18 `+target` above. That could be modeled as `+clang`.
19- niche features for resolving specific issues: for example, on Apple targets the linker flag
20 implementing the `as-needed` native link modifier (#99424) is only possible on sufficiently recent
21 linker versions.
22- still allows for discovery and automation, for example via feature detection. This can be useful
23 in exotic environments/build systems.
24
25The flag accepts a comma-separated list of features, individually enabled (`+features`) or disabled
26(`-features`), though currently only one is exposed on the CLI:
27- `lld`: to toggle using the lld linker, either the system-installed binary, or the self-contained
28 `rust-lld` linker.
29
30As described above, this list is intended to grow in the future.
31
32One of the most common uses of this flag will be to toggle self-contained linking with `rust-lld` on
33and off: `-Clinker-features=+lld -Clink-self-contained=+linker` will use the toolchain's `rust-lld`
34as the linker. Inversely, `-Clinker-features=-lld` would opt out of that, if the current target had
35self-contained linking enabled by default.
src/tools/opt-dist/src/tests.rs+3
......@@ -106,7 +106,10 @@ llvm-config = "{llvm_config}"
106106 "tests/incremental",
107107 "tests/mir-opt",
108108 "tests/pretty",
109 // Make sure that we don't use too new GLIBC symbols on x64
109110 "tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu",
111 // Make sure that we use LLD by default on x64
112 "tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist",
110113 "tests/ui",
111114 "tests/crashes",
112115 ];
tests/run-make/compressed-debuginfo-zstd/rmake.rs+1-1
......@@ -26,7 +26,7 @@ fn prepare_and_check<F: FnOnce(&mut Rustc) -> &mut Rustc>(to_find: &str, prepare
2626 run_in_tmpdir(|| {
2727 let mut rustc = Rustc::new();
2828 rustc
29 .arg("-Zlinker-features=+lld")
29 .arg("-Clinker-features=+lld")
3030 .arg("-Clink-self-contained=+linker")
3131 .arg("-Zunstable-options")
3232 .arg("-Cdebuginfo=full")
tests/run-make/rust-lld-by-default-beta-stable/main.rs deleted-1
......@@ -1 +0,0 @@
1fn main() {}
tests/run-make/rust-lld-by-default-beta-stable/rmake.rs deleted-14
......@@ -1,14 +0,0 @@
1// Ensure that rust-lld is *not* used as the default linker on `x86_64-unknown-linux-gnu` on stable
2// or beta.
3
4//@ ignore-nightly
5//@ only-x86_64-unknown-linux-gnu
6
7use run_make_support::linker::assert_rustc_doesnt_use_lld;
8use run_make_support::rustc;
9
10fn main() {
11 // A regular compilation should not use rust-lld by default. We'll check that by asking the
12 // linker to display its version number with a link-arg.
13 assert_rustc_doesnt_use_lld(rustc().input("main.rs"));
14}
tests/run-make/rust-lld-by-default-nightly/main.rs deleted-5
......@@ -1,5 +0,0 @@
1// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
2// target.
3// See https://github.com/rust-lang/compiler-team/issues/510 for more info
4
5fn main() {}
tests/run-make/rust-lld-by-default-nightly/rmake.rs deleted-19
......@@ -1,19 +0,0 @@
1// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu` on the nightly
2// channel, and that it can also be turned off with a CLI flag.
3
4//@ needs-rust-lld
5//@ ignore-beta
6//@ ignore-stable
7//@ only-x86_64-unknown-linux-gnu
8
9use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
10use run_make_support::rustc;
11
12fn main() {
13 // A regular compilation should use rust-lld by default. We'll check that by asking the linker
14 // to display its version number with a link-arg.
15 assert_rustc_uses_lld(rustc().input("main.rs"));
16
17 // But it can still be disabled by turning the linker feature off.
18 assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));
19}
tests/run-make/rust-lld-custom-target/rmake.rs+2-1
......@@ -23,7 +23,8 @@ fn main() {
2323 rustc()
2424 .crate_type("cdylib")
2525 .target("custom-target.json")
26 .arg("-Zlinker-features=-lld")
26 .arg("-Clinker-features=-lld")
27 .arg("-Zunstable-options")
2728 .input("lib.rs"),
2829 );
2930}
tests/run-make/rust-lld-link-script-provide/rmake.rs+1-1
......@@ -10,7 +10,7 @@ use run_make_support::rustc;
1010fn main() {
1111 rustc()
1212 .input("main.rs")
13 .arg("-Zlinker-features=+lld")
13 .arg("-Clinker-features=+lld")
1414 .arg("-Clink-self-contained=+linker")
1515 .arg("-Zunstable-options")
1616 .link_arg("-Tscript.t")
tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/main.rs created+5
......@@ -0,0 +1,5 @@
1// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
2// target.
3// See https://github.com/rust-lang/compiler-team/issues/510 for more info
4
5fn main() {}
tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/rmake.rs created+16
......@@ -0,0 +1,16 @@
1// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`
2// dist artifacts and that it can also be turned off with a CLI flag.
3
4//@ only-dist
5//@ only-x86_64-unknown-linux-gnu
6
7use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
8use run_make_support::rustc;
9
10fn main() {
11 // A regular compilation should use rust-lld by default.
12 assert_rustc_uses_lld(rustc().input("main.rs"));
13
14 // But it can still be disabled by turning the linker feature off.
15 assert_rustc_doesnt_use_lld(rustc().arg("-Clinker-features=-lld").input("main.rs"));
16}
tests/run-make/rust-lld-x86_64-unknown-linux-gnu/main.rs created+5
......@@ -0,0 +1,5 @@
1// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
2// target.
3// See https://github.com/rust-lang/compiler-team/issues/510 for more info
4
5fn main() {}
tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs created+20
......@@ -0,0 +1,20 @@
1// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`
2// and that it can also be turned off with a CLI flag.
3//
4// This version of the test checks that LLD is used by default when LLD is enabled in the
5// toolchain. There is a separate test that checks that LLD is used for dist artifacts
6// unconditionally.
7
8//@ needs-rust-lld
9//@ only-x86_64-unknown-linux-gnu
10
11use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
12use run_make_support::rustc;
13
14fn main() {
15 // A regular compilation should use rust-lld by default.
16 assert_rustc_uses_lld(rustc().input("main.rs"));
17
18 // But it can still be disabled by turning the linker feature off.
19 assert_rustc_doesnt_use_lld(rustc().arg("-Clinker-features=-lld").input("main.rs"));
20}
tests/run-make/rust-lld/rmake.rs+10-8
......@@ -1,5 +1,5 @@
1// Test linking using `cc` with `rust-lld`, using the unstable CLI described in MCP 510
2// see https://github.com/rust-lang/compiler-team/issues/510 for more info
1// Test linking using `cc` with `rust-lld`, using the `-Clinker-features` and
2// `-Clink-self-contained` CLI flags.
33
44//@ needs-rust-lld
55//@ ignore-s390x lld does not yet support s390x as target
......@@ -12,14 +12,16 @@ fn main() {
1212 // asking the linker to display its version number with a link-arg.
1313 assert_rustc_uses_lld(
1414 rustc()
15 .arg("-Zlinker-features=+lld")
15 .arg("-Clinker-features=+lld")
1616 .arg("-Clink-self-contained=+linker")
17 .arg("-Zunstable-options")
17 .arg("-Zunstable-options") // the opt-ins are unstable
1818 .input("main.rs"),
1919 );
2020
2121 // It should not be used when we explicitly opt out of lld.
22 assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs"));
22 assert_rustc_doesnt_use_lld(
23 rustc().arg("-Clinker-features=-lld").arg("-Zunstable-options").input("main.rs"),
24 );
2325
2426 // While we're here, also check that the last linker feature flag "wins" when passed multiple
2527 // times to rustc.
......@@ -27,9 +29,9 @@ fn main() {
2729 rustc()
2830 .arg("-Clink-self-contained=+linker")
2931 .arg("-Zunstable-options")
30 .arg("-Zlinker-features=-lld")
31 .arg("-Zlinker-features=+lld")
32 .arg("-Zlinker-features=-lld,+lld")
32 .arg("-Clinker-features=-lld")
33 .arg("-Clinker-features=+lld")
34 .arg("-Clinker-features=-lld,+lld")
3335 .input("main.rs"),
3436 );
3537}
tests/ui/linking/link-self-contained-consistency.rs-1
......@@ -1,7 +1,6 @@
11// Checks that self-contained linking components cannot be both enabled and disabled at the same
22// time on the CLI.
33
4//@ check-fail
54//@ revisions: one many
65//@ [one] compile-flags: -Clink-self-contained=-linker -Clink-self-contained=+linker -Zunstable-options
76//@ [many] compile-flags: -Clink-self-contained=+linker,+crto -Clink-self-contained=-linker,-crto -Zunstable-options
tests/ui/linking/link-self-contained-linker-disallowed.rs created+18
......@@ -0,0 +1,18 @@
1// Check that only `-C link-self-contained=-linker` is stable on x64 linux. Any other value or
2// target, needs `-Z unstable-options`.
3
4// ignore-tidy-linelength
5
6//@ revisions: unstable_target_positive unstable_target_negative unstable_positive
7//@ [unstable_target_negative] compile-flags: --target=x86_64-unknown-linux-musl -C link-self-contained=-linker --crate-type=rlib
8//@ [unstable_target_negative] needs-llvm-components: x86
9//@ [unstable_target_positive] compile-flags: --target=x86_64-unknown-linux-musl -C link-self-contained=+linker --crate-type=rlib
10//@ [unstable_target_positive] needs-llvm-components: x86
11//@ [unstable_positive] compile-flags: --target=x86_64-unknown-linux-gnu -C link-self-contained=+linker --crate-type=rlib
12//@ [unstable_positive] needs-llvm-components: x86
13
14#![feature(no_core)]
15#![no_core]
16
17//[unstable_target_negative]~? ERROR `-C link-self-contained=-linker` is unstable on the `x86_64-unknown-linux-musl` target
18//[unstable_target_positive,unstable_positive]~? ERROR only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable
tests/ui/linking/link-self-contained-linker-disallowed.unstable_positive.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/link-self-contained-linker-disallowed.unstable_target_negative.stderr created+2
......@@ -0,0 +1,2 @@
1error: `-C link-self-contained=-linker` is unstable on the `x86_64-unknown-linux-musl` target. The `-Z unstable-options` flag must also be passed to use it on this target
2
tests/ui/linking/link-self-contained-linker-disallowed.unstable_target_positive.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/link-self-contained-unstable.crto.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/link-self-contained-unstable.libc.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/link-self-contained-unstable.mingw.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/link-self-contained-unstable.rs created+13
......@@ -0,0 +1,13 @@
1// Checks that values for `-Clink-self-contained` other than the blanket enable/disable and
2// `-linker` require `-Zunstable-options`.
3
4//@ revisions: crto libc unwind sanitizers mingw
5//@ [crto] compile-flags: -Clink-self-contained=+crto
6//@ [libc] compile-flags: -Clink-self-contained=-libc
7//@ [unwind] compile-flags: -Clink-self-contained=+unwind
8//@ [sanitizers] compile-flags: -Clink-self-contained=-sanitizers
9//@ [mingw] compile-flags: -Clink-self-contained=+mingw
10
11fn main() {}
12
13//~? ERROR only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable
tests/ui/linking/link-self-contained-unstable.sanitizers.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/link-self-contained-unstable.unwind.stderr created+2
......@@ -0,0 +1,2 @@
1error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values
2
tests/ui/linking/linker-features-lld-disallowed.rs created+19
......@@ -0,0 +1,19 @@
1// Check that only `-C linker-features=-lld` is stable on x64 linux. Any other value or target,
2// needs `-Z unstable-options`.
3
4// ignore-tidy-linelength
5
6//@ revisions: unstable_target_positive unstable_target_negative unstable_positive
7//@ [unstable_target_negative] compile-flags: --target=x86_64-unknown-linux-musl -C linker-features=-lld --crate-type=rlib
8//@ [unstable_target_negative] needs-llvm-components: x86
9//@ [unstable_target_positive] compile-flags: --target=x86_64-unknown-linux-musl -C linker-features=+lld --crate-type=rlib
10//@ [unstable_target_positive] needs-llvm-components: x86
11//@ [unstable_positive] compile-flags: --target=x86_64-unknown-linux-gnu -C linker-features=+lld --crate-type=rlib
12//@ [unstable_positive] needs-llvm-components: x86
13
14
15#![feature(no_core)]
16#![no_core]
17
18//[unstable_target_negative]~? ERROR `-C linker-features=-lld` is unstable on the `x86_64-unknown-linux-musl` target
19//[unstable_target_positive,unstable_positive]~? ERROR `-C linker-features=+lld` is unstable, and also requires the `-Z unstable-options`
tests/ui/linking/linker-features-lld-disallowed.unstable_positive.stderr created+2
......@@ -0,0 +1,2 @@
1error: `-C linker-features=+lld` is unstable, and also requires the `-Z unstable-options` flag to be used
2
tests/ui/linking/linker-features-lld-disallowed.unstable_target_negative.stderr created+2
......@@ -0,0 +1,2 @@
1error: `-C linker-features=-lld` is unstable on the `x86_64-unknown-linux-musl` target. The `-Z unstable-options` flag must also be passed to use it on this target
2
tests/ui/linking/linker-features-lld-disallowed.unstable_target_positive.stderr created+2
......@@ -0,0 +1,2 @@
1error: `-C linker-features=+lld` is unstable, and also requires the `-Z unstable-options` flag to be used
2
tests/ui/linking/linker-features-malformed.invalid_modifier.stderr+1-1
......@@ -1,2 +1,2 @@
1error: incorrect value `*lld` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
1error: incorrect value `*lld` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
22
tests/ui/linking/linker-features-malformed.invalid_separator.stderr+1-1
......@@ -1,2 +1,2 @@
1error: incorrect value `-lld@+lld` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
1error: incorrect value `-lld@+lld` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
22
tests/ui/linking/linker-features-malformed.no_value.stderr+1-1
......@@ -1,2 +1,2 @@
1error: incorrect value `` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
1error: incorrect value `` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
22
tests/ui/linking/linker-features-malformed.rs+13-13
......@@ -1,27 +1,27 @@
1//! Check that malformed `-Zlinker-features` flags are properly rejected.
1//! Check that malformed `-Clinker-features` flags are properly rejected.
22
33//@ revisions: no_value
4//@[no_value] compile-flags: -Zlinker-features=
5//[no_value]~? ERROR incorrect value `` for unstable option `linker-features`
4//@[no_value] compile-flags: -Clinker-features=
5//[no_value]~? ERROR incorrect value `` for codegen option `linker-features`
66
77//@ revisions: invalid_modifier
8//@[invalid_modifier] compile-flags: -Zlinker-features=*lld
9//[invalid_modifier]~? ERROR incorrect value `*lld` for unstable option `linker-features`
8//@[invalid_modifier] compile-flags: -Clinker-features=*lld
9//[invalid_modifier]~? ERROR incorrect value `*lld` for codegen option `linker-features`
1010
1111//@ revisions: unknown_value
12//@[unknown_value] compile-flags: -Zlinker-features=unknown
13//[unknown_value]~? ERROR incorrect value `unknown` for unstable option `linker-features`
12//@[unknown_value] compile-flags: -Clinker-features=unknown
13//[unknown_value]~? ERROR incorrect value `unknown` for codegen option `linker-features`
1414
1515//@ revisions: unknown_modifier_value
16//@[unknown_modifier_value] compile-flags: -Zlinker-features=-unknown
17//[unknown_modifier_value]~? ERROR incorrect value `-unknown` for unstable option `linker-features`
16//@[unknown_modifier_value] compile-flags: -Clinker-features=-unknown
17//[unknown_modifier_value]~? ERROR incorrect value `-unknown` for codegen option `linker-features`
1818
1919//@ revisions: unknown_boolean
20//@[unknown_boolean] compile-flags: -Zlinker-features=maybe
21//[unknown_boolean]~? ERROR incorrect value `maybe` for unstable option `linker-features`
20//@[unknown_boolean] compile-flags: -Clinker-features=maybe
21//[unknown_boolean]~? ERROR incorrect value `maybe` for codegen option `linker-features`
2222
2323//@ revisions: invalid_separator
24//@[invalid_separator] compile-flags: -Zlinker-features=-lld@+lld
25//[invalid_separator]~? ERROR incorrect value `-lld@+lld` for unstable option `linker-features`
24//@[invalid_separator] compile-flags: -Clinker-features=-lld@+lld
25//[invalid_separator]~? ERROR incorrect value `-lld@+lld` for codegen option `linker-features`
2626
2727fn main() {}
tests/ui/linking/linker-features-malformed.unknown_boolean.stderr+1-1
......@@ -1,2 +1,2 @@
1error: incorrect value `maybe` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
1error: incorrect value `maybe` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
22
tests/ui/linking/linker-features-malformed.unknown_modifier_value.stderr+1-1
......@@ -1,2 +1,2 @@
1error: incorrect value `-unknown` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
1error: incorrect value `-unknown` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
22
tests/ui/linking/linker-features-malformed.unknown_value.stderr+1-1
......@@ -1,2 +1,2 @@
1error: incorrect value `unknown` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
1error: incorrect value `unknown` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
22
tests/ui/linking/linker-features-unstable-cc.rs created+13
......@@ -0,0 +1,13 @@
1// Check that only `-C linker-features=-lld` is stable on x64 linux, and that other linker
2// features require using `-Z unstable-options`.
3//
4// Note that, currently, only `lld` is parsed on the CLI, but that other linker features can exist
5// internally (`cc`).
6//
7//@ compile-flags: --target=x86_64-unknown-linux-gnu -C linker-features=+cc --crate-type=rlib
8//@ needs-llvm-components: x86
9
10#![feature(no_core)]
11#![no_core]
12
13//~? ERROR incorrect value `+cc` for codegen option `linker-features`
tests/ui/linking/linker-features-unstable-cc.stderr created+2
......@@ -0,0 +1,2 @@
1error: incorrect value `+cc` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
2