Skip to content

Commit 93a65c6

Browse files
committed
Auto merge of rust-lang#120348 - bjorn3:per_target_backend_selection, r=albertlarsan68
Support configuring the set of codegen backends to build per host triple This allows building the compiler itself with one backend while using another backend at runtime. For example this allows compiling rustc to wasm using LLVM, while using Cranelift at runtime to produce actual code. Cranelift can't compile to wasm, but is perfectly capable of running on wasm. LLVM can compile to wasm, but can't run on wasm. [^1] [^1]: The prototype of this still requires a couple of other patches.
2 parents d2e8ecd + f4e279f commit 93a65c6

File tree

9 files changed

+79
-37
lines changed

9 files changed

+79
-37
lines changed

config.example.toml

+5
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,11 @@
829829
# target triples containing `-none`, `nvptx`, `switch`, or `-uefi`.
830830
#no-std = <platform-specific> (bool)
831831

832+
# This is an array of the codegen backends that will be compiled a rustc
833+
# compiled for this target, overriding the global rust.codegen-backends option.
834+
# See that option for more info.
835+
#codegen-backends = rust.codegen-backends (array)
836+
832837
# =============================================================================
833838
# Distribution options
834839
#

src/bootstrap/src/core/build_steps/compile.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ impl Step for Rustc {
10391039
pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, stage: u32) {
10401040
cargo
10411041
.arg("--features")
1042-
.arg(builder.rustc_features(builder.kind))
1042+
.arg(builder.rustc_features(builder.kind, target))
10431043
.arg("--manifest-path")
10441044
.arg(builder.src.join("compiler/rustc/Cargo.toml"));
10451045

@@ -1096,7 +1096,7 @@ pub fn rustc_cargo_env(
10961096
cargo.env("CFG_OMIT_GIT_HASH", "1");
10971097
}
10981098

1099-
if let Some(backend) = builder.config.default_codegen_backend() {
1099+
if let Some(backend) = builder.config.default_codegen_backend(target) {
11001100
cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend);
11011101
}
11021102

@@ -1137,7 +1137,7 @@ pub fn rustc_cargo_env(
11371137
// build. If we are in a check build we still go ahead here presuming we've
11381138
// detected that LLVM is already built and good to go which helps prevent
11391139
// busting caches (e.g. like #71152).
1140-
if builder.config.llvm_enabled() {
1140+
if builder.config.llvm_enabled(target) {
11411141
let building_is_expensive =
11421142
crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).is_err();
11431143
// `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
@@ -1281,7 +1281,7 @@ pub(crate) const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_";
12811281
fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool {
12821282
if path.path.to_str().unwrap().contains(&CODEGEN_BACKEND_PREFIX) {
12831283
let mut needs_codegen_backend_config = true;
1284-
for &backend in &run.builder.config.rust_codegen_backends {
1284+
for &backend in run.builder.config.codegen_backends(run.target) {
12851285
if path
12861286
.path
12871287
.to_str()
@@ -1318,7 +1318,7 @@ impl Step for CodegenBackend {
13181318
return;
13191319
}
13201320

1321-
for &backend in &run.builder.config.rust_codegen_backends {
1321+
for &backend in run.builder.config.codegen_backends(run.target) {
13221322
if backend == "llvm" {
13231323
continue; // Already built as part of rustc
13241324
}
@@ -1425,7 +1425,7 @@ fn copy_codegen_backends_to_sysroot(
14251425
return;
14261426
}
14271427

1428-
for backend in builder.config.rust_codegen_backends.iter() {
1428+
for backend in builder.config.codegen_backends(target) {
14291429
if backend == "llvm" {
14301430
continue; // Already built as part of rustc
14311431
}
@@ -1732,7 +1732,7 @@ impl Step for Assemble {
17321732
// to not fail while linking the artifacts.
17331733
build_compiler.stage = actual_stage;
17341734

1735-
for &backend in builder.config.rust_codegen_backends.iter() {
1735+
for &backend in builder.config.codegen_backends(target_compiler.host) {
17361736
if backend == "llvm" {
17371737
continue; // Already built as part of rustc
17381738
}
@@ -1817,7 +1817,7 @@ impl Step for Assemble {
18171817
}
18181818
}
18191819

1820-
if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
1820+
if builder.config.llvm_enabled(target_compiler.host) {
18211821
let llvm::LlvmResult { llvm_config, .. } =
18221822
builder.ensure(llvm::Llvm { target: target_compiler.host });
18231823
if !builder.config.dry_run() && builder.config.llvm_tools_enabled {

src/bootstrap/src/core/build_steps/dist.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,7 @@ impl Step for CodegenBackend {
12781278
}
12791279

12801280
fn make_run(run: RunConfig<'_>) {
1281-
for &backend in &run.builder.config.rust_codegen_backends {
1281+
for &backend in run.builder.config.codegen_backends(run.target) {
12821282
if backend == "llvm" {
12831283
continue; // Already built as part of rustc
12841284
}
@@ -1302,7 +1302,7 @@ impl Step for CodegenBackend {
13021302
return None;
13031303
}
13041304

1305-
if !builder.config.rust_codegen_backends.contains(&self.backend) {
1305+
if !builder.config.codegen_backends(self.compiler.host).contains(&self.backend) {
13061306
return None;
13071307
}
13081308

src/bootstrap/src/core/build_steps/test.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1798,7 +1798,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
17981798

17991799
let mut llvm_components_passed = false;
18001800
let mut copts_passed = false;
1801-
if builder.config.llvm_enabled() {
1801+
if builder.config.llvm_enabled(compiler.host) {
18021802
let llvm::LlvmResult { llvm_config, .. } =
18031803
builder.ensure(llvm::Llvm { target: builder.config.build });
18041804
if !builder.config.dry_run() {
@@ -3121,7 +3121,8 @@ impl Step for CodegenCranelift {
31213121
return;
31223122
}
31233123

3124-
if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("cranelift")) {
3124+
if !builder.config.codegen_backends(run.target).contains(&INTERNER.intern_str("cranelift"))
3125+
{
31253126
builder.info("cranelift not in rust.codegen-backends. skipping");
31263127
return;
31273128
}
@@ -3245,7 +3246,7 @@ impl Step for CodegenGCC {
32453246
return;
32463247
}
32473248

3248-
if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("gcc")) {
3249+
if !builder.config.codegen_backends(run.target).contains(&INTERNER.intern_str("gcc")) {
32493250
builder.info("gcc not in rust.codegen-backends. skipping");
32503251
return;
32513252
}

src/bootstrap/src/core/builder.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ impl<'a> Builder<'a> {
12291229
/// Note that this returns `None` if LLVM is disabled, or if we're in a
12301230
/// check build or dry-run, where there's no need to build all of LLVM.
12311231
fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
1232-
if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run() {
1232+
if self.config.llvm_enabled(target) && self.kind != Kind::Check && !self.config.dry_run() {
12331233
let llvm::LlvmResult { llvm_config, .. } = self.ensure(llvm::Llvm { target });
12341234
if llvm_config.is_file() {
12351235
return Some(llvm_config);
@@ -1991,7 +1991,8 @@ impl<'a> Builder<'a> {
19911991
};
19921992

19931993
if let Some(limit) = limit {
1994-
if stage == 0 || self.config.default_codegen_backend().unwrap_or_default() == "llvm"
1994+
if stage == 0
1995+
|| self.config.default_codegen_backend(target).unwrap_or_default() == "llvm"
19951996
{
19961997
rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
19971998
}

src/bootstrap/src/core/config/config.rs

+31-4
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ pub struct Target {
577577
pub wasi_root: Option<PathBuf>,
578578
pub qemu_rootfs: Option<PathBuf>,
579579
pub no_std: bool,
580+
pub codegen_backends: Option<Vec<Interned<String>>>,
580581
}
581582

582583
impl Target {
@@ -1135,6 +1136,7 @@ define_config! {
11351136
wasi_root: Option<String> = "wasi-root",
11361137
qemu_rootfs: Option<String> = "qemu-rootfs",
11371138
no_std: Option<bool> = "no-std",
1139+
codegen_backends: Option<Vec<String>> = "codegen-backends",
11381140
}
11391141
}
11401142

@@ -1840,6 +1842,24 @@ impl Config {
18401842
target.profiler = cfg.profiler;
18411843
target.rpath = cfg.rpath;
18421844

1845+
if let Some(ref backends) = cfg.codegen_backends {
1846+
let available_backends = vec!["llvm", "cranelift", "gcc"];
1847+
1848+
target.codegen_backends = Some(backends.iter().map(|s| {
1849+
if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
1850+
if available_backends.contains(&backend) {
1851+
panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
1852+
} else {
1853+
println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
1854+
Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
1855+
In this case, it would be referred to as '{backend}'.");
1856+
}
1857+
}
1858+
1859+
INTERNER.intern_str(s)
1860+
}).collect());
1861+
}
1862+
18431863
config.target_config.insert(TargetSelection::from_user(&triple), target);
18441864
}
18451865
}
@@ -2222,8 +2242,8 @@ impl Config {
22222242
self.target_config.get(&target).map(|t| t.rpath).flatten().unwrap_or(self.rust_rpath)
22232243
}
22242244

2225-
pub fn llvm_enabled(&self) -> bool {
2226-
self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
2245+
pub fn llvm_enabled(&self, target: TargetSelection) -> bool {
2246+
self.codegen_backends(target).contains(&INTERNER.intern_str("llvm"))
22272247
}
22282248

22292249
pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind {
@@ -2242,8 +2262,15 @@ impl Config {
22422262
self.submodules.unwrap_or(rust_info.is_managed_git_subrepository())
22432263
}
22442264

2245-
pub fn default_codegen_backend(&self) -> Option<Interned<String>> {
2246-
self.rust_codegen_backends.get(0).cloned()
2265+
pub fn codegen_backends(&self, target: TargetSelection) -> &[Interned<String>] {
2266+
self.target_config
2267+
.get(&target)
2268+
.and_then(|cfg| cfg.codegen_backends.as_deref())
2269+
.unwrap_or(&self.rust_codegen_backends)
2270+
}
2271+
2272+
pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<Interned<String>> {
2273+
self.codegen_backends(target).get(0).cloned()
22472274
}
22482275

22492276
pub fn git_config(&self) -> GitConfig<'_> {

src/bootstrap/src/core/sanity.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use std::path::PathBuf;
1616
use std::process::Command;
1717

1818
use crate::core::config::Target;
19-
use crate::utils::cache::INTERNER;
2019
use crate::utils::helpers::output;
2120
use crate::Build;
2221

@@ -88,19 +87,19 @@ pub fn check(build: &mut Build) {
8887
}
8988

9089
// We need cmake, but only if we're actually building LLVM or sanitizers.
91-
let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
92-
&& build
93-
.hosts
94-
.iter()
95-
.map(|host| {
96-
build
90+
let building_llvm = build
91+
.hosts
92+
.iter()
93+
.map(|host| {
94+
build.config.llvm_enabled(*host)
95+
&& build
9796
.config
9897
.target_config
9998
.get(host)
10099
.map(|config| config.llvm_config.is_none())
101100
.unwrap_or(true)
102-
})
103-
.any(|build_llvm_ourselves| build_llvm_ourselves);
101+
})
102+
.any(|build_llvm_ourselves| build_llvm_ourselves);
104103

105104
let need_cmake = building_llvm || build.config.any_sanitizers_to_build();
106105
if need_cmake && cmd_finder.maybe_have("cmake").is_none() {
@@ -190,13 +189,16 @@ than building it.
190189
if !build.config.dry_run() {
191190
cmd_finder.must_have(build.cxx(*host).unwrap());
192191
}
193-
}
194192

195-
if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
196-
// Externally configured LLVM requires FileCheck to exist
197-
let filecheck = build.llvm_filecheck(build.build);
198-
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
199-
panic!("FileCheck executable {filecheck:?} does not exist");
193+
if build.config.llvm_enabled(*host) {
194+
// Externally configured LLVM requires FileCheck to exist
195+
let filecheck = build.llvm_filecheck(build.build);
196+
if !filecheck.starts_with(&build.out)
197+
&& !filecheck.exists()
198+
&& build.config.codegen_tests
199+
{
200+
panic!("FileCheck executable {filecheck:?} does not exist");
201+
}
200202
}
201203
}
202204

src/bootstrap/src/lib.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -731,12 +731,12 @@ impl Build {
731731
}
732732

733733
/// Gets the space-separated set of activated features for the compiler.
734-
fn rustc_features(&self, kind: Kind) -> String {
734+
fn rustc_features(&self, kind: Kind, target: TargetSelection) -> String {
735735
let mut features = vec![];
736736
if self.config.jemalloc {
737737
features.push("jemalloc");
738738
}
739-
if self.config.llvm_enabled() || kind == Kind::Check {
739+
if self.config.llvm_enabled(target) || kind == Kind::Check {
740740
features.push("llvm");
741741
}
742742
// keep in sync with `bootstrap/compile.rs:rustc_cargo_env`
@@ -1561,7 +1561,8 @@ impl Build {
15611561
|| target
15621562
.map(|t| self.config.profiler_enabled(t))
15631563
.unwrap_or_else(|| self.config.any_profiler_enabled()))
1564-
&& (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
1564+
&& (dep != "rustc_codegen_llvm"
1565+
|| self.config.hosts.iter().any(|host| self.config.llvm_enabled(*host)))
15651566
{
15661567
list.push(*dep);
15671568
}

src/bootstrap/src/utils/change_tracker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
114114
severity: ChangeSeverity::Warning,
115115
summary: "A new `optimized-compiler-builtins` option has been introduced. Whether to build llvm's `compiler-rt` from source is no longer implicitly controlled by git state. See the PR for more details.",
116116
},
117+
ChangeInfo {
118+
change_id: 120348,
119+
severity: ChangeSeverity::Info,
120+
summary: "New option `target.<triple>.codegen-backends` added to config.toml.",
121+
},
117122
];

0 commit comments

Comments
 (0)