From 148a07cbd0842ed64bffec0aad8b4c20ed1186a3 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Wed, 20 Aug 2025 11:19:49 -0500 Subject: [PATCH] Refactor *.optimized-compiler-builtins bootstrap options Create a dedicated enum to abstract the different ways compiler-builtins can be configured. This also relaxes build.optimized-compiler-builtins to accept the path of a library to match the behavior of .optimized-compiler-builtins override. --- bootstrap.example.toml | 7 +++-- src/bootstrap/src/core/build_steps/compile.rs | 17 +++++++----- src/bootstrap/src/core/config/config.rs | 25 +++++++---------- src/bootstrap/src/core/config/mod.rs | 27 +++++++++++++++++++ src/bootstrap/src/core/config/tests.rs | 10 ++++--- src/bootstrap/src/core/config/toml/build.rs | 4 +-- src/bootstrap/src/core/config/toml/rust.rs | 4 +-- src/bootstrap/src/core/config/toml/target.rs | 8 +++--- src/bootstrap/src/core/sanity.rs | 5 ++-- 9 files changed, 71 insertions(+), 36 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index ebab2e14828c..16fd9241a172 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -407,8 +407,11 @@ #build.profiler = false # Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics. -# Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` -# sources are available. +# Choosing true requires the LLVM submodule to be managed by bootstrap (i.e. not external) +# so that `compiler-rt` sources are available. +# +# Setting this to a path removes the requirement for a C toolchain, but requires setting the +# path to an existing library containing the builtins library from LLVM's compiler-rt. # # Setting this to `false` generates slower code, but removes the requirement for a C toolchain in # order to run `x check`. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 005c849c47a1..f7a2dc142184 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -26,7 +26,9 @@ use crate::core::builder; use crate::core::builder::{ Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, }; -use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; +use crate::core::config::{ + CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection, +}; use crate::utils::build_stamp; use crate::utils::build_stamp::BuildStamp; use crate::utils::exec::command; @@ -574,10 +576,12 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car // If `compiler-rt` is available ensure that the `c` feature of the // `compiler-builtins` crate is enabled and it's configured to learn where // `compiler-rt` is located. - let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins(target) { - if let Some(path) = builder.config.optimized_compiler_builtins_path(target) { + let compiler_builtins_c_feature = match builder.config.optimized_compiler_builtins(target) { + CompilerBuiltins::LinkLLVMBuiltinsLib(path) => { cargo.env("LLVM_COMPILER_RT_LIB", path); - } else { + " compiler-builtins-c" + } + CompilerBuiltins::BuildLLVMFuncs => { // NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce // `submodules = false`, so this is a no-op. But, the user could still decide to // manually use an in-tree submodule. @@ -599,10 +603,9 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car // The path to `compiler-rt` is also used by `profiler_builtins` (above), // so if you're changing something here please also change that as appropriate. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); + " compiler-builtins-c" } - " compiler-builtins-c" - } else { - "" + CompilerBuiltins::BuildRustOnly => "", }; // `libtest` uses this to know whether or not to support diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 09a1eb5b847a..e5c2e3c64b80 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -46,8 +46,8 @@ use crate::core::config::toml::rust::{ }; use crate::core::config::toml::target::Target; use crate::core::config::{ - DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, - StringOrBool, threads_from_config, + CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, + RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, }; use crate::core::download::{ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, @@ -121,8 +121,7 @@ pub struct Config { pub patch_binaries_for_nix: Option, pub stage0_metadata: build_helper::stage0_parser::Stage0, pub android_ndk: Option, - /// Whether to use the `c` feature of the `compiler_builtins` crate. - pub optimized_compiler_builtins: bool, + pub optimized_compiler_builtins: CompilerBuiltins, pub stdout_is_tty: bool, pub stderr_is_tty: bool, @@ -1109,7 +1108,11 @@ impl Config { let rustfmt_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rustfmt")); let optimized_compiler_builtins = - build_optimized_compiler_builtins.unwrap_or(channel != "dev"); + build_optimized_compiler_builtins.unwrap_or(if channel == "dev" { + CompilerBuiltins::BuildRustOnly + } else { + CompilerBuiltins::BuildLLVMFuncs + }); let vendor = build_vendor.unwrap_or( rust_info.is_from_tarball() && src.join("vendor").exists() @@ -1672,19 +1675,11 @@ impl Config { self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath) } - pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool { + pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> &CompilerBuiltins { self.target_config .get(&target) .and_then(|t| t.optimized_compiler_builtins.as_ref()) - .map(StringOrBool::is_string_or_true) - .unwrap_or(self.optimized_compiler_builtins) - } - - pub fn optimized_compiler_builtins_path(&self, target: TargetSelection) -> Option<&str> { - match self.target_config.get(&target)?.optimized_compiler_builtins.as_ref()? { - StringOrBool::String(s) => Some(s), - StringOrBool::Bool(_) => None, - } + .unwrap_or(&self.optimized_compiler_builtins) } pub fn llvm_enabled(&self, target: TargetSelection) -> bool { diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index dbd05fd25197..5999348a7fe8 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -218,6 +218,33 @@ impl Merge for Option { } } +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub enum CompilerBuiltins { + #[default] + // Only build native rust intrinsic compiler functions. + BuildRustOnly, + // Some intrinsic functions have a C implementation provided by LLVM's + // compiler-rt builtins library. Build them from the LLVM source included + // with Rust. + BuildLLVMFuncs, + // Similar to BuildLLVMFuncs, but specify a path to an existing library + // containing LLVM's compiler-rt builtins instead of compiling them. + LinkLLVMBuiltinsLib(String), +} + +impl<'de> Deserialize<'de> for CompilerBuiltins { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(match Deserialize::deserialize(deserializer)? { + StringOrBool::Bool(false) => Self::BuildRustOnly, + StringOrBool::Bool(true) => Self::BuildLLVMFuncs, + StringOrBool::String(path) => Self::LinkLLVMBuiltinsLib(path), + }) + } +} + #[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] pub enum DebuginfoLevel { #[default] diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index c32e4384cf62..e93525fbd09c 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -17,7 +17,7 @@ use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; use crate::core::config::toml::TomlConfig; -use crate::core::config::{LldMode, StringOrBool, Target, TargetSelection}; +use crate::core::config::{CompilerBuiltins, LldMode, StringOrBool, Target, TargetSelection}; use crate::utils::tests::git::git_test; pub(crate) fn parse(config: &str) -> Config { @@ -183,7 +183,11 @@ runner = "x86_64-runner" ); assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes"); assert!(!config.deny_warnings, "setting boolean value"); - assert!(config.optimized_compiler_builtins, "setting boolean value"); + assert_eq!( + config.optimized_compiler_builtins, + CompilerBuiltins::BuildLLVMFuncs, + "setting boolean value" + ); assert_eq!( config.tools, Some(["cargo".to_string()].into_iter().collect()), @@ -212,7 +216,7 @@ runner = "x86_64-runner" let darwin = TargetSelection::from_user("aarch64-apple-darwin"); let darwin_values = Target { runner: Some("apple".into()), - optimized_compiler_builtins: Some(StringOrBool::Bool(false)), + optimized_compiler_builtins: Some(CompilerBuiltins::BuildRustOnly), ..Default::default() }; assert_eq!( diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 728367b39729..25c19f1070a3 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use serde::{Deserialize, Deserializer}; use crate::core::config::toml::ReplaceOpt; -use crate::core::config::{Merge, StringOrBool}; +use crate::core::config::{CompilerBuiltins, Merge, StringOrBool}; use crate::{HashSet, PathBuf, define_config, exit}; define_config! { @@ -65,7 +65,7 @@ define_config! { // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally metrics: Option = "metrics", android_ndk: Option = "android-ndk", - optimized_compiler_builtins: Option = "optimized-compiler-builtins", + optimized_compiler_builtins: Option = "optimized-compiler-builtins", jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", compiletest_allow_stage0: Option = "compiletest-allow-stage0", diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 3dab8d1d96d5..7f111094c3f1 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -269,9 +269,9 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_profiler, profiler, "build"); let current_optimized_compiler_builtins = - current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins.clone()); let optimized_compiler_builtins = - ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins.clone()); err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build"); // We always build the in-tree compiler on cross targets, so we only care diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 3236b5cdbaa9..020602e6a199 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -11,7 +11,9 @@ use serde::{Deserialize, Deserializer}; -use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; +use crate::core::config::{ + CompilerBuiltins, LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool, +}; use crate::{CodegenBackendKind, HashSet, PathBuf, define_config, exit}; define_config! { @@ -39,7 +41,7 @@ define_config! { no_std: Option = "no-std", codegen_backends: Option> = "codegen-backends", runner: Option = "runner", - optimized_compiler_builtins: Option = "optimized-compiler-builtins", + optimized_compiler_builtins: Option = "optimized-compiler-builtins", jemalloc: Option = "jemalloc", } } @@ -71,7 +73,7 @@ pub struct Target { pub runner: Option, pub no_std: bool, pub codegen_backends: Option>, - pub optimized_compiler_builtins: Option, + pub optimized_compiler_builtins: Option, pub jemalloc: Option, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index de7cada93f23..4916ebbd6109 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -18,7 +18,7 @@ use crate::builder::Builder; use crate::builder::Kind; #[cfg(not(test))] use crate::core::build_steps::tool; -use crate::core::config::Target; +use crate::core::config::{CompilerBuiltins, Target}; use crate::utils::exec::command; use crate::{Build, Subcommand}; @@ -330,7 +330,8 @@ than building it. // compiler-rt c fallbacks for wasm cannot be built with gcc if target.contains("wasm") - && (build.config.optimized_compiler_builtins(*target) + && (*build.config.optimized_compiler_builtins(*target) + != CompilerBuiltins::BuildRustOnly || build.config.rust_std_features.contains("compiler-builtins-c")) { let cc_tool = build.cc_tool(*target);