This commit adds a toml module that represents various subsections of bootstrap.toml.
The module primarily defines the TOML representations of these subsections and their corresponding configuration parsing implementations, which are ultimately integrated into the main configuration. - `mod.rs` – Serves as the entry point for the TOML configuration and defines the `TomlConfig` struct along with its parsing implementation. - `rust.rs` – Defines the `Rust` subsection struct and its configuration parsing implementation. - `target.rs` – Defines the `Target` subsection struct and its configuration parsing implementation. - `llvm.rs` – Defines the `Llvm` subsection struct and its configuration parsing implementation. - `install.rs` – Defines the `Install` subsection struct and its configuration parsing implementation. - `gcc.rs` – Defines the `Gcc` subsection struct and its configuration parsing implementation. - `dist.rs` – Defines the `Dist` subsection struct and its configuration parsing implementation. - `build.rs` – Defines the `Build` subsection struct and its configuration parsing implementation.
This commit is contained in:
parent
b17dba4518
commit
8a807cd498
9 changed files with 1541 additions and 0 deletions
72
src/bootstrap/src/core/config/toml/build.rs
Normal file
72
src/bootstrap/src/core/config/toml/build.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//! This module defines the `Build` struct, which represents the `[build]` table
|
||||
//! in the `bootstrap.toml` configuration file.
|
||||
//!
|
||||
//! The `[build]` table contains global options that influence the overall build process,
|
||||
//! such as default host and target triples, paths to tools, build directories, and
|
||||
//! various feature flags. These options apply across different stages and components
|
||||
//! unless specifically overridden by other configuration sections or command-line flags.
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::config::toml::ReplaceOpt;
|
||||
use crate::core::config::{Merge, StringOrBool};
|
||||
use crate::{HashSet, PathBuf, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of various global build decisions.
|
||||
#[derive(Default)]
|
||||
struct Build {
|
||||
build: Option<String> = "build",
|
||||
description: Option<String> = "description",
|
||||
host: Option<Vec<String>> = "host",
|
||||
target: Option<Vec<String>> = "target",
|
||||
build_dir: Option<String> = "build-dir",
|
||||
cargo: Option<PathBuf> = "cargo",
|
||||
rustc: Option<PathBuf> = "rustc",
|
||||
rustfmt: Option<PathBuf> = "rustfmt",
|
||||
cargo_clippy: Option<PathBuf> = "cargo-clippy",
|
||||
docs: Option<bool> = "docs",
|
||||
compiler_docs: Option<bool> = "compiler-docs",
|
||||
library_docs_private_items: Option<bool> = "library-docs-private-items",
|
||||
docs_minification: Option<bool> = "docs-minification",
|
||||
submodules: Option<bool> = "submodules",
|
||||
gdb: Option<String> = "gdb",
|
||||
lldb: Option<String> = "lldb",
|
||||
nodejs: Option<String> = "nodejs",
|
||||
npm: Option<String> = "npm",
|
||||
python: Option<String> = "python",
|
||||
reuse: Option<String> = "reuse",
|
||||
locked_deps: Option<bool> = "locked-deps",
|
||||
vendor: Option<bool> = "vendor",
|
||||
full_bootstrap: Option<bool> = "full-bootstrap",
|
||||
bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path",
|
||||
extended: Option<bool> = "extended",
|
||||
tools: Option<HashSet<String>> = "tools",
|
||||
verbose: Option<usize> = "verbose",
|
||||
sanitizers: Option<bool> = "sanitizers",
|
||||
profiler: Option<bool> = "profiler",
|
||||
cargo_native_static: Option<bool> = "cargo-native-static",
|
||||
low_priority: Option<bool> = "low-priority",
|
||||
configure_args: Option<Vec<String>> = "configure-args",
|
||||
local_rebuild: Option<bool> = "local-rebuild",
|
||||
print_step_timings: Option<bool> = "print-step-timings",
|
||||
print_step_rusage: Option<bool> = "print-step-rusage",
|
||||
check_stage: Option<u32> = "check-stage",
|
||||
doc_stage: Option<u32> = "doc-stage",
|
||||
build_stage: Option<u32> = "build-stage",
|
||||
test_stage: Option<u32> = "test-stage",
|
||||
install_stage: Option<u32> = "install-stage",
|
||||
dist_stage: Option<u32> = "dist-stage",
|
||||
bench_stage: Option<u32> = "bench-stage",
|
||||
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
|
||||
// NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
|
||||
metrics: Option<bool> = "metrics",
|
||||
android_ndk: Option<PathBuf> = "android-ndk",
|
||||
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
|
||||
jobs: Option<u32> = "jobs",
|
||||
compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
|
||||
compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
|
||||
ccache: Option<StringOrBool> = "ccache",
|
||||
exclude: Option<Vec<PathBuf>> = "exclude",
|
||||
}
|
||||
}
|
||||
34
src/bootstrap/src/core/config/toml/change_id.rs
Normal file
34
src/bootstrap/src/core/config/toml/change_id.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
use serde::{Deserialize, Deserializer};
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ChangeId {
|
||||
Ignore,
|
||||
Id(usize),
|
||||
}
|
||||
|
||||
/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type
|
||||
/// for the "change-id" field to parse it even if other fields are invalid. This ensures
|
||||
/// that if deserialization fails due to other fields, we can still provide the changelogs
|
||||
/// to allow developers to potentially find the reason for the failure in the logs..
|
||||
#[derive(Deserialize, Default)]
|
||||
pub(crate) struct ChangeIdWrapper {
|
||||
#[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")]
|
||||
pub(crate) inner: Option<ChangeId>,
|
||||
}
|
||||
|
||||
fn deserialize_change_id<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<ChangeId>, D::Error> {
|
||||
let value = toml::Value::deserialize(deserializer)?;
|
||||
Ok(match value {
|
||||
toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore),
|
||||
toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)),
|
||||
_ => {
|
||||
return Err(serde::de::Error::custom(
|
||||
"expected \"ignore\" or an integer for change-id",
|
||||
));
|
||||
}
|
||||
})
|
||||
}
|
||||
52
src/bootstrap/src/core/config/toml/dist.rs
Normal file
52
src/bootstrap/src/core/config/toml/dist.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//! This module defines the `Dist` struct, which represents the `[dist]` table
|
||||
//! in the `bootstrap.toml` configuration file.
|
||||
//!
|
||||
//! The `[dist]` table contains options related to the distribution process,
|
||||
//! including signing, uploading artifacts, source tarballs, compression settings,
|
||||
//! and inclusion of specific tools.
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::config::toml::ReplaceOpt;
|
||||
use crate::core::config::{Merge, set};
|
||||
use crate::{Config, HashSet, PathBuf, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
struct Dist {
|
||||
sign_folder: Option<String> = "sign-folder",
|
||||
upload_addr: Option<String> = "upload-addr",
|
||||
src_tarball: Option<bool> = "src-tarball",
|
||||
compression_formats: Option<Vec<String>> = "compression-formats",
|
||||
compression_profile: Option<String> = "compression-profile",
|
||||
include_mingw_linker: Option<bool> = "include-mingw-linker",
|
||||
vendor: Option<bool> = "vendor",
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Applies distribution-related configuration from the `Dist` struct
|
||||
/// to the global `Config` structure.
|
||||
pub fn apply_dist_config(&mut self, toml_dist: Option<Dist>) {
|
||||
if let Some(dist) = toml_dist {
|
||||
let Dist {
|
||||
sign_folder,
|
||||
upload_addr,
|
||||
src_tarball,
|
||||
compression_formats,
|
||||
compression_profile,
|
||||
include_mingw_linker,
|
||||
vendor,
|
||||
} = dist;
|
||||
self.dist_sign_folder = sign_folder.map(PathBuf::from);
|
||||
self.dist_upload_addr = upload_addr;
|
||||
self.dist_compression_formats = compression_formats;
|
||||
set(&mut self.dist_compression_profile, compression_profile);
|
||||
set(&mut self.rust_dist_src, src_tarball);
|
||||
set(&mut self.dist_include_mingw_linker, include_mingw_linker);
|
||||
self.dist_vendor = vendor.unwrap_or_else(|| {
|
||||
// If we're building from git or tarball sources, enable it by default.
|
||||
self.rust_info.is_managed_git_subrepository() || self.rust_info.is_from_tarball()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/bootstrap/src/core/config/toml/gcc.rs
Normal file
34
src/bootstrap/src/core/config/toml/gcc.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//! This module defines the `Gcc` struct, which represents the `[gcc]` table
|
||||
//! in the `bootstrap.toml` configuration file.
|
||||
//!
|
||||
//! The `[gcc]` table contains options specifically related to building or
|
||||
//! acquiring the GCC compiler for use within the Rust build process.
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::config::toml::ReplaceOpt;
|
||||
use crate::core::config::{GccCiMode, Merge};
|
||||
use crate::{Config, HashSet, PathBuf, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of how the GCC build is configured.
|
||||
struct Gcc {
|
||||
download_ci_gcc: Option<bool> = "download-ci-gcc",
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Applies GCC-related configuration from the `TomlGcc` struct to the
|
||||
/// global `Config` structure.
|
||||
pub fn apply_gcc_config(&mut self, toml_gcc: Option<Gcc>) {
|
||||
if let Some(gcc) = toml_gcc {
|
||||
self.gcc_ci_mode = match gcc.download_ci_gcc {
|
||||
Some(value) => match value {
|
||||
true => GccCiMode::DownloadFromCi,
|
||||
false => GccCiMode::BuildLocally,
|
||||
},
|
||||
None => GccCiMode::default(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/bootstrap/src/core/config/toml/install.rs
Normal file
43
src/bootstrap/src/core/config/toml/install.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//! This module defines the `Install` struct, which represents the `[install]` table
|
||||
//! in the `bootstrap.toml` configuration file.
|
||||
//!
|
||||
//! The `[install]` table contains options that specify the installation paths
|
||||
//! for various components of the Rust toolchain. These paths determine where
|
||||
//! executables, libraries, documentation, and other files will be placed
|
||||
//! during the `install` stage of the build.
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::config::toml::ReplaceOpt;
|
||||
use crate::core::config::{Merge, set};
|
||||
use crate::{Config, HashSet, PathBuf, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of various global install decisions.
|
||||
struct Install {
|
||||
prefix: Option<String> = "prefix",
|
||||
sysconfdir: Option<String> = "sysconfdir",
|
||||
docdir: Option<String> = "docdir",
|
||||
bindir: Option<String> = "bindir",
|
||||
libdir: Option<String> = "libdir",
|
||||
mandir: Option<String> = "mandir",
|
||||
datadir: Option<String> = "datadir",
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Applies installation-related configuration from the `Install` struct
|
||||
/// to the global `Config` structure.
|
||||
pub fn apply_install_config(&mut self, toml_install: Option<Install>) {
|
||||
if let Some(install) = toml_install {
|
||||
let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install;
|
||||
self.prefix = prefix.map(PathBuf::from);
|
||||
self.sysconfdir = sysconfdir.map(PathBuf::from);
|
||||
self.datadir = datadir.map(PathBuf::from);
|
||||
self.docdir = docdir.map(PathBuf::from);
|
||||
set(&mut self.bindir, bindir.map(PathBuf::from));
|
||||
self.libdir = libdir.map(PathBuf::from);
|
||||
self.mandir = mandir.map(PathBuf::from);
|
||||
}
|
||||
}
|
||||
}
|
||||
284
src/bootstrap/src/core/config/toml/llvm.rs
Normal file
284
src/bootstrap/src/core/config/toml/llvm.rs
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
//! This module defines the `Llvm` struct, which represents the `[llvm]` table
|
||||
//! in the `bootstrap.toml` configuration file.
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::config::toml::{Merge, ReplaceOpt, TomlConfig};
|
||||
use crate::core::config::{StringOrBool, set};
|
||||
use crate::{Config, HashMap, HashSet, PathBuf, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of how the LLVM build is configured.
|
||||
struct Llvm {
|
||||
optimize: Option<bool> = "optimize",
|
||||
thin_lto: Option<bool> = "thin-lto",
|
||||
release_debuginfo: Option<bool> = "release-debuginfo",
|
||||
assertions: Option<bool> = "assertions",
|
||||
tests: Option<bool> = "tests",
|
||||
enzyme: Option<bool> = "enzyme",
|
||||
plugins: Option<bool> = "plugins",
|
||||
// FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache
|
||||
ccache: Option<StringOrBool> = "ccache",
|
||||
static_libstdcpp: Option<bool> = "static-libstdcpp",
|
||||
libzstd: Option<bool> = "libzstd",
|
||||
ninja: Option<bool> = "ninja",
|
||||
targets: Option<String> = "targets",
|
||||
experimental_targets: Option<String> = "experimental-targets",
|
||||
link_jobs: Option<u32> = "link-jobs",
|
||||
link_shared: Option<bool> = "link-shared",
|
||||
version_suffix: Option<String> = "version-suffix",
|
||||
clang_cl: Option<String> = "clang-cl",
|
||||
cflags: Option<String> = "cflags",
|
||||
cxxflags: Option<String> = "cxxflags",
|
||||
ldflags: Option<String> = "ldflags",
|
||||
use_libcxx: Option<bool> = "use-libcxx",
|
||||
use_linker: Option<String> = "use-linker",
|
||||
allow_old_toolchain: Option<bool> = "allow-old-toolchain",
|
||||
offload: Option<bool> = "offload",
|
||||
polly: Option<bool> = "polly",
|
||||
clang: Option<bool> = "clang",
|
||||
enable_warnings: Option<bool> = "enable-warnings",
|
||||
download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
|
||||
build_config: Option<HashMap<String, String>> = "build-config",
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options.
|
||||
/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing.
|
||||
#[cfg(not(test))]
|
||||
pub fn check_incompatible_options_for_ci_llvm(
|
||||
current_config_toml: TomlConfig,
|
||||
ci_config_toml: TomlConfig,
|
||||
) -> Result<(), String> {
|
||||
macro_rules! err {
|
||||
($current:expr, $expected:expr) => {
|
||||
if let Some(current) = &$current {
|
||||
if Some(current) != $expected.as_ref() {
|
||||
return Err(format!(
|
||||
"ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \
|
||||
Current value: {:?}, Expected value(s): {}{:?}",
|
||||
stringify!($expected).replace("_", "-"),
|
||||
$current,
|
||||
if $expected.is_some() { "None/" } else { "" },
|
||||
$expected,
|
||||
));
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! warn {
|
||||
($current:expr, $expected:expr) => {
|
||||
if let Some(current) = &$current {
|
||||
if Some(current) != $expected.as_ref() {
|
||||
println!(
|
||||
"WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \
|
||||
Current value: {:?}, Expected value(s): {}{:?}",
|
||||
stringify!($expected).replace("_", "-"),
|
||||
$current,
|
||||
if $expected.is_some() { "None/" } else { "" },
|
||||
$expected,
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
let (Some(current_llvm_config), Some(ci_llvm_config)) =
|
||||
(current_config_toml.llvm, ci_config_toml.llvm)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let Llvm {
|
||||
optimize,
|
||||
thin_lto,
|
||||
release_debuginfo,
|
||||
assertions: _,
|
||||
tests: _,
|
||||
plugins,
|
||||
ccache: _,
|
||||
static_libstdcpp: _,
|
||||
libzstd,
|
||||
ninja: _,
|
||||
targets,
|
||||
experimental_targets,
|
||||
link_jobs: _,
|
||||
link_shared: _,
|
||||
version_suffix,
|
||||
clang_cl,
|
||||
cflags,
|
||||
cxxflags,
|
||||
ldflags,
|
||||
use_libcxx,
|
||||
use_linker,
|
||||
allow_old_toolchain,
|
||||
offload,
|
||||
polly,
|
||||
clang,
|
||||
enable_warnings,
|
||||
download_ci_llvm: _,
|
||||
build_config,
|
||||
enzyme,
|
||||
} = ci_llvm_config;
|
||||
|
||||
err!(current_llvm_config.optimize, optimize);
|
||||
err!(current_llvm_config.thin_lto, thin_lto);
|
||||
err!(current_llvm_config.release_debuginfo, release_debuginfo);
|
||||
err!(current_llvm_config.libzstd, libzstd);
|
||||
err!(current_llvm_config.targets, targets);
|
||||
err!(current_llvm_config.experimental_targets, experimental_targets);
|
||||
err!(current_llvm_config.clang_cl, clang_cl);
|
||||
err!(current_llvm_config.version_suffix, version_suffix);
|
||||
err!(current_llvm_config.cflags, cflags);
|
||||
err!(current_llvm_config.cxxflags, cxxflags);
|
||||
err!(current_llvm_config.ldflags, ldflags);
|
||||
err!(current_llvm_config.use_libcxx, use_libcxx);
|
||||
err!(current_llvm_config.use_linker, use_linker);
|
||||
err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
|
||||
err!(current_llvm_config.offload, offload);
|
||||
err!(current_llvm_config.polly, polly);
|
||||
err!(current_llvm_config.clang, clang);
|
||||
err!(current_llvm_config.build_config, build_config);
|
||||
err!(current_llvm_config.plugins, plugins);
|
||||
err!(current_llvm_config.enzyme, enzyme);
|
||||
|
||||
warn!(current_llvm_config.enable_warnings, enable_warnings);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn apply_llvm_config(
|
||||
&mut self,
|
||||
toml_llvm: Option<Llvm>,
|
||||
ccache: &mut Option<StringOrBool>,
|
||||
) {
|
||||
let mut llvm_tests = None;
|
||||
let mut llvm_enzyme = None;
|
||||
let mut llvm_offload = None;
|
||||
let mut llvm_plugins = None;
|
||||
|
||||
if let Some(llvm) = toml_llvm {
|
||||
let Llvm {
|
||||
optimize: optimize_toml,
|
||||
thin_lto,
|
||||
release_debuginfo,
|
||||
assertions: _,
|
||||
tests,
|
||||
enzyme,
|
||||
plugins,
|
||||
ccache: llvm_ccache,
|
||||
static_libstdcpp,
|
||||
libzstd,
|
||||
ninja,
|
||||
targets,
|
||||
experimental_targets,
|
||||
link_jobs,
|
||||
link_shared,
|
||||
version_suffix,
|
||||
clang_cl,
|
||||
cflags,
|
||||
cxxflags,
|
||||
ldflags,
|
||||
use_libcxx,
|
||||
use_linker,
|
||||
allow_old_toolchain,
|
||||
offload,
|
||||
polly,
|
||||
clang,
|
||||
enable_warnings,
|
||||
download_ci_llvm,
|
||||
build_config,
|
||||
} = llvm;
|
||||
if llvm_ccache.is_some() {
|
||||
eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead.");
|
||||
}
|
||||
|
||||
if ccache.is_none() {
|
||||
*ccache = llvm_ccache;
|
||||
}
|
||||
set(&mut self.ninja_in_file, ninja);
|
||||
llvm_tests = tests;
|
||||
llvm_enzyme = enzyme;
|
||||
llvm_offload = offload;
|
||||
llvm_plugins = plugins;
|
||||
set(&mut self.llvm_optimize, optimize_toml);
|
||||
set(&mut self.llvm_thin_lto, thin_lto);
|
||||
set(&mut self.llvm_release_debuginfo, release_debuginfo);
|
||||
set(&mut self.llvm_static_stdcpp, static_libstdcpp);
|
||||
set(&mut self.llvm_libzstd, libzstd);
|
||||
if let Some(v) = link_shared {
|
||||
self.llvm_link_shared.set(Some(v));
|
||||
}
|
||||
self.llvm_targets.clone_from(&targets);
|
||||
self.llvm_experimental_targets.clone_from(&experimental_targets);
|
||||
self.llvm_link_jobs = link_jobs;
|
||||
self.llvm_version_suffix.clone_from(&version_suffix);
|
||||
self.llvm_clang_cl.clone_from(&clang_cl);
|
||||
|
||||
self.llvm_cflags.clone_from(&cflags);
|
||||
self.llvm_cxxflags.clone_from(&cxxflags);
|
||||
self.llvm_ldflags.clone_from(&ldflags);
|
||||
set(&mut self.llvm_use_libcxx, use_libcxx);
|
||||
self.llvm_use_linker.clone_from(&use_linker);
|
||||
self.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false);
|
||||
self.llvm_offload = offload.unwrap_or(false);
|
||||
self.llvm_polly = polly.unwrap_or(false);
|
||||
self.llvm_clang = clang.unwrap_or(false);
|
||||
self.llvm_enable_warnings = enable_warnings.unwrap_or(false);
|
||||
self.llvm_build_config = build_config.clone().unwrap_or(Default::default());
|
||||
|
||||
self.llvm_from_ci = self.parse_download_ci_llvm(download_ci_llvm, self.llvm_assertions);
|
||||
|
||||
if self.llvm_from_ci {
|
||||
let warn = |option: &str| {
|
||||
println!(
|
||||
"WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
|
||||
);
|
||||
println!(
|
||||
"HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
|
||||
);
|
||||
};
|
||||
|
||||
if static_libstdcpp.is_some() {
|
||||
warn("static-libstdcpp");
|
||||
}
|
||||
|
||||
if link_shared.is_some() {
|
||||
warn("link-shared");
|
||||
}
|
||||
|
||||
// FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow,
|
||||
// use the `builder-config` present in tarballs since #128822 to compare the local
|
||||
// config to the ones used to build the LLVM artifacts on CI, and only notify users
|
||||
// if they've chosen a different value.
|
||||
|
||||
if libzstd.is_some() {
|
||||
println!(
|
||||
"WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \
|
||||
like almost all `llvm.*` options, will be ignored and set by the LLVM CI \
|
||||
artifacts builder config."
|
||||
);
|
||||
println!(
|
||||
"HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !self.llvm_from_ci && self.llvm_thin_lto && link_shared.is_none() {
|
||||
// If we're building with ThinLTO on, by default we want to link
|
||||
// to LLVM shared, to avoid re-doing ThinLTO (which happens in
|
||||
// the link step) with each stage.
|
||||
self.llvm_link_shared.set(Some(true));
|
||||
}
|
||||
} else {
|
||||
self.llvm_from_ci = self.parse_download_ci_llvm(None, false);
|
||||
}
|
||||
|
||||
self.llvm_tests = llvm_tests.unwrap_or(false);
|
||||
self.llvm_enzyme = llvm_enzyme.unwrap_or(false);
|
||||
self.llvm_offload = llvm_offload.unwrap_or(false);
|
||||
self.llvm_plugins = llvm_plugins.unwrap_or(false);
|
||||
}
|
||||
}
|
||||
184
src/bootstrap/src/core/config/toml/mod.rs
Normal file
184
src/bootstrap/src/core/config/toml/mod.rs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
//! This module defines the structures that directly mirror the `bootstrap.toml`
|
||||
//! file's format. These types are used for `serde` deserialization.
|
||||
//!
|
||||
//! Crucially, this module also houses the core logic for loading, parsing, and merging
|
||||
//! these raw TOML configurations from various sources (the main `bootstrap.toml`,
|
||||
//! included files, profile defaults, and command-line overrides). This processed
|
||||
//! TOML data then serves as an intermediate representation, which is further
|
||||
//! transformed and applied to the final [`Config`] struct.
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde_derive::Deserialize;
|
||||
pub mod build;
|
||||
pub mod change_id;
|
||||
pub mod dist;
|
||||
pub mod gcc;
|
||||
pub mod install;
|
||||
pub mod llvm;
|
||||
pub mod rust;
|
||||
pub mod target;
|
||||
|
||||
use build::Build;
|
||||
use change_id::{ChangeId, ChangeIdWrapper};
|
||||
use dist::Dist;
|
||||
use gcc::Gcc;
|
||||
use install::Install;
|
||||
use llvm::Llvm;
|
||||
use rust::Rust;
|
||||
use target::TomlTarget;
|
||||
|
||||
use crate::core::config::{Merge, ReplaceOpt};
|
||||
use crate::{Config, HashMap, HashSet, Path, PathBuf, exit, fs, t};
|
||||
|
||||
/// Structure of the `bootstrap.toml` file that configuration is read from.
|
||||
///
|
||||
/// This structure uses `Decodable` to automatically decode a TOML configuration
|
||||
/// file into this format, and then this is traversed and written into the above
|
||||
/// `Config` structure.
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
pub(crate) struct TomlConfig {
|
||||
#[serde(flatten)]
|
||||
pub(crate) change_id: ChangeIdWrapper,
|
||||
pub(super) build: Option<Build>,
|
||||
pub(super) install: Option<Install>,
|
||||
pub(super) llvm: Option<Llvm>,
|
||||
pub(super) gcc: Option<Gcc>,
|
||||
pub(super) rust: Option<Rust>,
|
||||
pub(super) target: Option<HashMap<String, TomlTarget>>,
|
||||
pub(super) dist: Option<Dist>,
|
||||
pub(super) profile: Option<String>,
|
||||
pub(super) include: Option<Vec<PathBuf>>,
|
||||
}
|
||||
|
||||
impl Merge for TomlConfig {
|
||||
fn merge(
|
||||
&mut self,
|
||||
parent_config_path: Option<PathBuf>,
|
||||
included_extensions: &mut HashSet<PathBuf>,
|
||||
TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self,
|
||||
replace: ReplaceOpt,
|
||||
) {
|
||||
fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
|
||||
if let Some(new) = y {
|
||||
if let Some(original) = x {
|
||||
original.merge(None, &mut Default::default(), new, replace);
|
||||
} else {
|
||||
*x = Some(new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace);
|
||||
self.profile.merge(None, &mut Default::default(), profile, replace);
|
||||
|
||||
do_merge(&mut self.build, build, replace);
|
||||
do_merge(&mut self.install, install, replace);
|
||||
do_merge(&mut self.llvm, llvm, replace);
|
||||
do_merge(&mut self.gcc, gcc, replace);
|
||||
do_merge(&mut self.rust, rust, replace);
|
||||
do_merge(&mut self.dist, dist, replace);
|
||||
|
||||
match (self.target.as_mut(), target) {
|
||||
(_, None) => {}
|
||||
(None, Some(target)) => self.target = Some(target),
|
||||
(Some(original_target), Some(new_target)) => {
|
||||
for (triple, new) in new_target {
|
||||
if let Some(original) = original_target.get_mut(&triple) {
|
||||
original.merge(None, &mut Default::default(), new, replace);
|
||||
} else {
|
||||
original_target.insert(triple, new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let parent_dir = parent_config_path
|
||||
.as_ref()
|
||||
.and_then(|p| p.parent().map(ToOwned::to_owned))
|
||||
.unwrap_or_default();
|
||||
|
||||
// `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to
|
||||
// keep the upper-level configuration to take precedence.
|
||||
for include_path in include.clone().unwrap_or_default().iter().rev() {
|
||||
let include_path = parent_dir.join(include_path);
|
||||
let include_path = include_path.canonicalize().unwrap_or_else(|e| {
|
||||
eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display());
|
||||
exit!(2);
|
||||
});
|
||||
|
||||
let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| {
|
||||
eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
|
||||
exit!(2);
|
||||
});
|
||||
|
||||
assert!(
|
||||
included_extensions.insert(include_path.clone()),
|
||||
"Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.",
|
||||
include_path.display()
|
||||
);
|
||||
|
||||
self.merge(
|
||||
Some(include_path.clone()),
|
||||
included_extensions,
|
||||
included_toml,
|
||||
// Ensures that parent configuration always takes precedence
|
||||
// over child configurations.
|
||||
ReplaceOpt::IgnoreDuplicate,
|
||||
);
|
||||
|
||||
included_extensions.remove(&include_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This file is embedded in the overlay directory of the tarball sources. It is
|
||||
/// useful in scenarios where developers want to see how the tarball sources were
|
||||
/// generated.
|
||||
///
|
||||
/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder
|
||||
/// configuration to detect any incompatible options.
|
||||
pub const BUILDER_CONFIG_FILENAME: &str = "builder-config";
|
||||
|
||||
impl Config {
|
||||
pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, toml::de::Error> {
|
||||
if self.dry_run() {
|
||||
return Ok(TomlConfig::default());
|
||||
}
|
||||
|
||||
let builder_config_path =
|
||||
self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME);
|
||||
Self::get_toml(&builder_config_path)
|
||||
}
|
||||
|
||||
pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
|
||||
#[cfg(test)]
|
||||
return Ok(TomlConfig::default());
|
||||
|
||||
#[cfg(not(test))]
|
||||
Self::get_toml_inner(file)
|
||||
}
|
||||
|
||||
pub(crate) fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> {
|
||||
let contents =
|
||||
t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
|
||||
// Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
|
||||
// TomlConfig and sub types to be monomorphized 5x by toml.
|
||||
toml::from_str(&contents)
|
||||
.and_then(|table: toml::Value| TomlConfig::deserialize(table))
|
||||
.inspect_err(|_| {
|
||||
if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) =
|
||||
toml::from_str::<toml::Value>(&contents)
|
||||
.and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table))
|
||||
{
|
||||
let changes = crate::find_recent_config_change_ids(id);
|
||||
if !changes.is_empty() {
|
||||
println!(
|
||||
"WARNING: There have been changes to x.py since you last updated:\n{}",
|
||||
crate::human_readable_changes(changes)
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
664
src/bootstrap/src/core/config/toml/rust.rs
Normal file
664
src/bootstrap/src/core/config/toml/rust.rs
Normal file
|
|
@ -0,0 +1,664 @@
|
|||
//! This module defines the `Rust` struct, which represents the `[rust]` table
|
||||
//! in the `bootstrap.toml` configuration file.
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
|
||||
use crate::core::config::toml::TomlConfig;
|
||||
use crate::core::config::{
|
||||
DebuginfoLevel, Merge, ReplaceOpt, RustcLto, StringOrBool, set, threads_from_config,
|
||||
};
|
||||
use crate::flags::Warnings;
|
||||
use crate::{BTreeSet, Config, HashSet, PathBuf, TargetSelection, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of how the Rust build is configured.
|
||||
struct Rust {
|
||||
optimize: Option<RustOptimize> = "optimize",
|
||||
debug: Option<bool> = "debug",
|
||||
codegen_units: Option<u32> = "codegen-units",
|
||||
codegen_units_std: Option<u32> = "codegen-units-std",
|
||||
rustc_debug_assertions: Option<bool> = "debug-assertions",
|
||||
randomize_layout: Option<bool> = "randomize-layout",
|
||||
std_debug_assertions: Option<bool> = "debug-assertions-std",
|
||||
tools_debug_assertions: Option<bool> = "debug-assertions-tools",
|
||||
overflow_checks: Option<bool> = "overflow-checks",
|
||||
overflow_checks_std: Option<bool> = "overflow-checks-std",
|
||||
debug_logging: Option<bool> = "debug-logging",
|
||||
debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level",
|
||||
debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc",
|
||||
debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
|
||||
debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
|
||||
debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
|
||||
backtrace: Option<bool> = "backtrace",
|
||||
incremental: Option<bool> = "incremental",
|
||||
default_linker: Option<String> = "default-linker",
|
||||
channel: Option<String> = "channel",
|
||||
// FIXME: Remove this field at Q2 2025, it has been replaced by build.description
|
||||
description: Option<String> = "description",
|
||||
musl_root: Option<String> = "musl-root",
|
||||
rpath: Option<bool> = "rpath",
|
||||
strip: Option<bool> = "strip",
|
||||
frame_pointers: Option<bool> = "frame-pointers",
|
||||
stack_protector: Option<String> = "stack-protector",
|
||||
verbose_tests: Option<bool> = "verbose-tests",
|
||||
optimize_tests: Option<bool> = "optimize-tests",
|
||||
codegen_tests: Option<bool> = "codegen-tests",
|
||||
omit_git_hash: Option<bool> = "omit-git-hash",
|
||||
dist_src: Option<bool> = "dist-src",
|
||||
save_toolstates: Option<String> = "save-toolstates",
|
||||
codegen_backends: Option<Vec<String>> = "codegen-backends",
|
||||
llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker",
|
||||
lld: Option<bool> = "lld",
|
||||
lld_mode: Option<LldMode> = "use-lld",
|
||||
llvm_tools: Option<bool> = "llvm-tools",
|
||||
deny_warnings: Option<bool> = "deny-warnings",
|
||||
backtrace_on_ice: Option<bool> = "backtrace-on-ice",
|
||||
verify_llvm_ir: Option<bool> = "verify-llvm-ir",
|
||||
thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
|
||||
remap_debuginfo: Option<bool> = "remap-debuginfo",
|
||||
jemalloc: Option<bool> = "jemalloc",
|
||||
test_compare_mode: Option<bool> = "test-compare-mode",
|
||||
llvm_libunwind: Option<String> = "llvm-libunwind",
|
||||
control_flow_guard: Option<bool> = "control-flow-guard",
|
||||
ehcont_guard: Option<bool> = "ehcont-guard",
|
||||
new_symbol_mangling: Option<bool> = "new-symbol-mangling",
|
||||
profile_generate: Option<String> = "profile-generate",
|
||||
profile_use: Option<String> = "profile-use",
|
||||
// ignored; this is set from an env var set by bootstrap.py
|
||||
download_rustc: Option<StringOrBool> = "download-rustc",
|
||||
lto: Option<String> = "lto",
|
||||
validate_mir_opts: Option<u32> = "validate-mir-opts",
|
||||
std_features: Option<BTreeSet<String>> = "std-features",
|
||||
}
|
||||
}
|
||||
|
||||
/// LLD in bootstrap works like this:
|
||||
/// - Self-contained lld: use `rust-lld` from the compiler's sysroot
|
||||
/// - External: use an external `lld` binary
|
||||
///
|
||||
/// It is configured depending on the target:
|
||||
/// 1) Everything except MSVC
|
||||
/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker`
|
||||
/// - External: `-Clinker-flavor=gnu-lld-cc`
|
||||
/// 2) MSVC
|
||||
/// - Self-contained: `-Clinker=<path to rust-lld>`
|
||||
/// - External: `-Clinker=lld`
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq)]
|
||||
pub enum LldMode {
|
||||
/// Do not use LLD
|
||||
#[default]
|
||||
Unused,
|
||||
/// Use `rust-lld` from the compiler's sysroot
|
||||
SelfContained,
|
||||
/// Use an externally provided `lld` binary.
|
||||
/// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has
|
||||
/// to be in $PATH.
|
||||
External,
|
||||
}
|
||||
|
||||
impl LldMode {
|
||||
pub fn is_used(&self) -> bool {
|
||||
match self {
|
||||
LldMode::SelfContained | LldMode::External => true,
|
||||
LldMode::Unused => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for LldMode {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct LldModeVisitor;
|
||||
|
||||
impl serde::de::Visitor<'_> for LldModeVisitor {
|
||||
type Value = LldMode;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
formatter.write_str("one of true, 'self-contained' or 'external'")
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(if v { LldMode::External } else { LldMode::Unused })
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
match v {
|
||||
"external" => Ok(LldMode::External),
|
||||
"self-contained" => Ok(LldMode::SelfContained),
|
||||
_ => Err(E::custom(format!("unknown mode {v}"))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(LldModeVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum RustOptimize {
|
||||
String(String),
|
||||
Int(u8),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
impl Default for RustOptimize {
|
||||
fn default() -> RustOptimize {
|
||||
RustOptimize::Bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for RustOptimize {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(OptimizeVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct OptimizeVisitor;
|
||||
|
||||
impl serde::de::Visitor<'_> for OptimizeVisitor {
|
||||
type Value = RustOptimize;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if matches!(value, "s" | "z") {
|
||||
Ok(RustOptimize::String(value.to_string()))
|
||||
} else {
|
||||
Err(serde::de::Error::custom(format_optimize_error_msg(value)))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if matches!(value, 0..=3) {
|
||||
Ok(RustOptimize::Int(value as u8))
|
||||
} else {
|
||||
Err(serde::de::Error::custom(format_optimize_error_msg(value)))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(RustOptimize::Bool(value))
|
||||
}
|
||||
}
|
||||
|
||||
fn format_optimize_error_msg(v: impl std::fmt::Display) -> String {
|
||||
format!(
|
||||
r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"#
|
||||
)
|
||||
}
|
||||
|
||||
impl RustOptimize {
|
||||
pub(crate) fn is_release(&self) -> bool {
|
||||
match &self {
|
||||
RustOptimize::Bool(true) | RustOptimize::String(_) => true,
|
||||
RustOptimize::Int(i) => *i > 0,
|
||||
RustOptimize::Bool(false) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_opt_level(&self) -> Option<String> {
|
||||
match &self {
|
||||
RustOptimize::String(s) => Some(s.clone()),
|
||||
RustOptimize::Int(i) => Some(i.to_string()),
|
||||
RustOptimize::Bool(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options.
|
||||
/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing.
|
||||
pub fn check_incompatible_options_for_ci_rustc(
|
||||
host: TargetSelection,
|
||||
current_config_toml: TomlConfig,
|
||||
ci_config_toml: TomlConfig,
|
||||
) -> Result<(), String> {
|
||||
macro_rules! err {
|
||||
($current:expr, $expected:expr, $config_section:expr) => {
|
||||
if let Some(current) = &$current {
|
||||
if Some(current) != $expected.as_ref() {
|
||||
return Err(format!(
|
||||
"ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \
|
||||
Current value: {:?}, Expected value(s): {}{:?}",
|
||||
format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
|
||||
$current,
|
||||
if $expected.is_some() { "None/" } else { "" },
|
||||
$expected,
|
||||
));
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! warn {
|
||||
($current:expr, $expected:expr, $config_section:expr) => {
|
||||
if let Some(current) = &$current {
|
||||
if Some(current) != $expected.as_ref() {
|
||||
println!(
|
||||
"WARNING: `{}` has no effect with `rust.download-rustc`. \
|
||||
Current value: {:?}, Expected value(s): {}{:?}",
|
||||
format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
|
||||
$current,
|
||||
if $expected.is_some() { "None/" } else { "" },
|
||||
$expected,
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler);
|
||||
let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler);
|
||||
err!(current_profiler, profiler, "build");
|
||||
|
||||
let current_optimized_compiler_builtins =
|
||||
current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
|
||||
let optimized_compiler_builtins =
|
||||
ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
|
||||
err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build");
|
||||
|
||||
// We always build the in-tree compiler on cross targets, so we only care
|
||||
// about the host target here.
|
||||
let host_str = host.to_string();
|
||||
if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str))
|
||||
&& current_cfg.profiler.is_some()
|
||||
{
|
||||
let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str));
|
||||
let ci_cfg = ci_target_toml.ok_or(format!(
|
||||
"Target specific config for '{host_str}' is not present for CI-rustc"
|
||||
))?;
|
||||
|
||||
let profiler = &ci_cfg.profiler;
|
||||
err!(current_cfg.profiler, profiler, "build");
|
||||
|
||||
let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins;
|
||||
err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build");
|
||||
}
|
||||
|
||||
let (Some(current_rust_config), Some(ci_rust_config)) =
|
||||
(current_config_toml.rust, ci_config_toml.rust)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let Rust {
|
||||
// Following options are the CI rustc incompatible ones.
|
||||
optimize,
|
||||
randomize_layout,
|
||||
debug_logging,
|
||||
debuginfo_level_rustc,
|
||||
llvm_tools,
|
||||
llvm_bitcode_linker,
|
||||
lto,
|
||||
stack_protector,
|
||||
strip,
|
||||
lld_mode,
|
||||
jemalloc,
|
||||
rpath,
|
||||
channel,
|
||||
description,
|
||||
incremental,
|
||||
default_linker,
|
||||
std_features,
|
||||
|
||||
// Rest of the options can simply be ignored.
|
||||
debug: _,
|
||||
codegen_units: _,
|
||||
codegen_units_std: _,
|
||||
rustc_debug_assertions: _,
|
||||
std_debug_assertions: _,
|
||||
tools_debug_assertions: _,
|
||||
overflow_checks: _,
|
||||
overflow_checks_std: _,
|
||||
debuginfo_level: _,
|
||||
debuginfo_level_std: _,
|
||||
debuginfo_level_tools: _,
|
||||
debuginfo_level_tests: _,
|
||||
backtrace: _,
|
||||
musl_root: _,
|
||||
verbose_tests: _,
|
||||
optimize_tests: _,
|
||||
codegen_tests: _,
|
||||
omit_git_hash: _,
|
||||
dist_src: _,
|
||||
save_toolstates: _,
|
||||
codegen_backends: _,
|
||||
lld: _,
|
||||
deny_warnings: _,
|
||||
backtrace_on_ice: _,
|
||||
verify_llvm_ir: _,
|
||||
thin_lto_import_instr_limit: _,
|
||||
remap_debuginfo: _,
|
||||
test_compare_mode: _,
|
||||
llvm_libunwind: _,
|
||||
control_flow_guard: _,
|
||||
ehcont_guard: _,
|
||||
new_symbol_mangling: _,
|
||||
profile_generate: _,
|
||||
profile_use: _,
|
||||
download_rustc: _,
|
||||
validate_mir_opts: _,
|
||||
frame_pointers: _,
|
||||
} = ci_rust_config;
|
||||
|
||||
// There are two kinds of checks for CI rustc incompatible options:
|
||||
// 1. Checking an option that may change the compiler behaviour/output.
|
||||
// 2. Checking an option that have no effect on the compiler behaviour/output.
|
||||
//
|
||||
// If the option belongs to the first category, we call `err` macro for a hard error;
|
||||
// otherwise, we just print a warning with `warn` macro.
|
||||
|
||||
err!(current_rust_config.optimize, optimize, "rust");
|
||||
err!(current_rust_config.randomize_layout, randomize_layout, "rust");
|
||||
err!(current_rust_config.debug_logging, debug_logging, "rust");
|
||||
err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust");
|
||||
err!(current_rust_config.rpath, rpath, "rust");
|
||||
err!(current_rust_config.strip, strip, "rust");
|
||||
err!(current_rust_config.lld_mode, lld_mode, "rust");
|
||||
err!(current_rust_config.llvm_tools, llvm_tools, "rust");
|
||||
err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust");
|
||||
err!(current_rust_config.jemalloc, jemalloc, "rust");
|
||||
err!(current_rust_config.default_linker, default_linker, "rust");
|
||||
err!(current_rust_config.stack_protector, stack_protector, "rust");
|
||||
err!(current_rust_config.lto, lto, "rust");
|
||||
err!(current_rust_config.std_features, std_features, "rust");
|
||||
|
||||
warn!(current_rust_config.channel, channel, "rust");
|
||||
warn!(current_rust_config.description, description, "rust");
|
||||
warn!(current_rust_config.incremental, incremental, "rust");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn apply_rust_config(
|
||||
&mut self,
|
||||
toml_rust: Option<Rust>,
|
||||
warnings: Warnings,
|
||||
description: &mut Option<String>,
|
||||
) {
|
||||
let mut debug = None;
|
||||
let mut rustc_debug_assertions = None;
|
||||
let mut std_debug_assertions = None;
|
||||
let mut tools_debug_assertions = None;
|
||||
let mut overflow_checks = None;
|
||||
let mut overflow_checks_std = None;
|
||||
let mut debug_logging = None;
|
||||
let mut debuginfo_level = None;
|
||||
let mut debuginfo_level_rustc = None;
|
||||
let mut debuginfo_level_std = None;
|
||||
let mut debuginfo_level_tools = None;
|
||||
let mut debuginfo_level_tests = None;
|
||||
let mut optimize = None;
|
||||
let mut lld_enabled = None;
|
||||
let mut std_features = None;
|
||||
|
||||
if let Some(rust) = toml_rust {
|
||||
let Rust {
|
||||
optimize: optimize_toml,
|
||||
debug: debug_toml,
|
||||
codegen_units,
|
||||
codegen_units_std,
|
||||
rustc_debug_assertions: rustc_debug_assertions_toml,
|
||||
std_debug_assertions: std_debug_assertions_toml,
|
||||
tools_debug_assertions: tools_debug_assertions_toml,
|
||||
overflow_checks: overflow_checks_toml,
|
||||
overflow_checks_std: overflow_checks_std_toml,
|
||||
debug_logging: debug_logging_toml,
|
||||
debuginfo_level: debuginfo_level_toml,
|
||||
debuginfo_level_rustc: debuginfo_level_rustc_toml,
|
||||
debuginfo_level_std: debuginfo_level_std_toml,
|
||||
debuginfo_level_tools: debuginfo_level_tools_toml,
|
||||
debuginfo_level_tests: debuginfo_level_tests_toml,
|
||||
backtrace,
|
||||
incremental,
|
||||
randomize_layout,
|
||||
default_linker,
|
||||
channel: _, // already handled above
|
||||
description: rust_description,
|
||||
musl_root,
|
||||
rpath,
|
||||
verbose_tests,
|
||||
optimize_tests,
|
||||
codegen_tests,
|
||||
omit_git_hash: _, // already handled above
|
||||
dist_src,
|
||||
save_toolstates,
|
||||
codegen_backends,
|
||||
lld: lld_enabled_toml,
|
||||
llvm_tools,
|
||||
llvm_bitcode_linker,
|
||||
deny_warnings,
|
||||
backtrace_on_ice,
|
||||
verify_llvm_ir,
|
||||
thin_lto_import_instr_limit,
|
||||
remap_debuginfo,
|
||||
jemalloc,
|
||||
test_compare_mode,
|
||||
llvm_libunwind,
|
||||
control_flow_guard,
|
||||
ehcont_guard,
|
||||
new_symbol_mangling,
|
||||
profile_generate,
|
||||
profile_use,
|
||||
download_rustc,
|
||||
lto,
|
||||
validate_mir_opts,
|
||||
frame_pointers,
|
||||
stack_protector,
|
||||
strip,
|
||||
lld_mode,
|
||||
std_features: std_features_toml,
|
||||
} = rust;
|
||||
|
||||
// FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions
|
||||
// enabled. We should not download a CI alt rustc if we need rustc to have debug
|
||||
// assertions (e.g. for crashes test suite). This can be changed once something like
|
||||
// [Enable debug assertions on alt
|
||||
// builds](https://github.com/rust-lang/rust/pull/131077) lands.
|
||||
//
|
||||
// Note that `rust.debug = true` currently implies `rust.debug-assertions = true`!
|
||||
//
|
||||
// This relies also on the fact that the global default for `download-rustc` will be
|
||||
// `false` if it's not explicitly set.
|
||||
let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true))
|
||||
|| (matches!(debug_toml, Some(true))
|
||||
&& !matches!(rustc_debug_assertions_toml, Some(false)));
|
||||
|
||||
if debug_assertions_requested
|
||||
&& let Some(ref opt) = download_rustc
|
||||
&& opt.is_string_or_true()
|
||||
{
|
||||
eprintln!(
|
||||
"WARN: currently no CI rustc builds have rustc debug assertions \
|
||||
enabled. Please either set `rust.debug-assertions` to `false` if you \
|
||||
want to use download CI rustc or set `rust.download-rustc` to `false`."
|
||||
);
|
||||
}
|
||||
|
||||
self.download_rustc_commit = self.download_ci_rustc_commit(
|
||||
download_rustc,
|
||||
debug_assertions_requested,
|
||||
self.llvm_assertions,
|
||||
);
|
||||
|
||||
debug = debug_toml;
|
||||
rustc_debug_assertions = rustc_debug_assertions_toml;
|
||||
std_debug_assertions = std_debug_assertions_toml;
|
||||
tools_debug_assertions = tools_debug_assertions_toml;
|
||||
overflow_checks = overflow_checks_toml;
|
||||
overflow_checks_std = overflow_checks_std_toml;
|
||||
debug_logging = debug_logging_toml;
|
||||
debuginfo_level = debuginfo_level_toml;
|
||||
debuginfo_level_rustc = debuginfo_level_rustc_toml;
|
||||
debuginfo_level_std = debuginfo_level_std_toml;
|
||||
debuginfo_level_tools = debuginfo_level_tools_toml;
|
||||
debuginfo_level_tests = debuginfo_level_tests_toml;
|
||||
lld_enabled = lld_enabled_toml;
|
||||
std_features = std_features_toml;
|
||||
|
||||
optimize = optimize_toml;
|
||||
self.rust_new_symbol_mangling = new_symbol_mangling;
|
||||
set(&mut self.rust_optimize_tests, optimize_tests);
|
||||
set(&mut self.codegen_tests, codegen_tests);
|
||||
set(&mut self.rust_rpath, rpath);
|
||||
set(&mut self.rust_strip, strip);
|
||||
set(&mut self.rust_frame_pointers, frame_pointers);
|
||||
self.rust_stack_protector = stack_protector;
|
||||
set(&mut self.jemalloc, jemalloc);
|
||||
set(&mut self.test_compare_mode, test_compare_mode);
|
||||
set(&mut self.backtrace, backtrace);
|
||||
if rust_description.is_some() {
|
||||
eprintln!(
|
||||
"Warning: rust.description is deprecated. Use build.description instead."
|
||||
);
|
||||
}
|
||||
if description.is_none() {
|
||||
*description = rust_description;
|
||||
}
|
||||
set(&mut self.rust_dist_src, dist_src);
|
||||
set(&mut self.verbose_tests, verbose_tests);
|
||||
// in the case "false" is set explicitly, do not overwrite the command line args
|
||||
if let Some(true) = incremental {
|
||||
self.incremental = true;
|
||||
}
|
||||
set(&mut self.lld_mode, lld_mode);
|
||||
set(&mut self.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
|
||||
|
||||
self.rust_randomize_layout = randomize_layout.unwrap_or_default();
|
||||
self.llvm_tools_enabled = llvm_tools.unwrap_or(true);
|
||||
|
||||
self.llvm_enzyme = self.channel == "dev" || self.channel == "nightly";
|
||||
self.rustc_default_linker = default_linker;
|
||||
self.musl_root = musl_root.map(PathBuf::from);
|
||||
self.save_toolstates = save_toolstates.map(PathBuf::from);
|
||||
set(
|
||||
&mut self.deny_warnings,
|
||||
match warnings {
|
||||
Warnings::Deny => Some(true),
|
||||
Warnings::Warn => Some(false),
|
||||
Warnings::Default => deny_warnings,
|
||||
},
|
||||
);
|
||||
set(&mut self.backtrace_on_ice, backtrace_on_ice);
|
||||
set(&mut self.rust_verify_llvm_ir, verify_llvm_ir);
|
||||
self.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit;
|
||||
set(&mut self.rust_remap_debuginfo, remap_debuginfo);
|
||||
set(&mut self.control_flow_guard, control_flow_guard);
|
||||
set(&mut self.ehcont_guard, ehcont_guard);
|
||||
self.llvm_libunwind_default =
|
||||
llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
|
||||
|
||||
if let Some(ref backends) = codegen_backends {
|
||||
let available_backends = ["llvm", "cranelift", "gcc"];
|
||||
|
||||
self.rust_codegen_backends = backends.iter().map(|s| {
|
||||
if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
|
||||
if available_backends.contains(&backend) {
|
||||
panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
|
||||
} else {
|
||||
println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
|
||||
Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
|
||||
In this case, it would be referred to as '{backend}'.");
|
||||
}
|
||||
}
|
||||
|
||||
s.clone()
|
||||
}).collect();
|
||||
}
|
||||
|
||||
self.rust_codegen_units = codegen_units.map(threads_from_config);
|
||||
self.rust_codegen_units_std = codegen_units_std.map(threads_from_config);
|
||||
|
||||
if self.rust_profile_use.is_none() {
|
||||
self.rust_profile_use = profile_use;
|
||||
}
|
||||
|
||||
if self.rust_profile_generate.is_none() {
|
||||
self.rust_profile_generate = profile_generate;
|
||||
}
|
||||
|
||||
self.rust_lto =
|
||||
lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default();
|
||||
self.rust_validate_mir_opts = validate_mir_opts;
|
||||
}
|
||||
|
||||
self.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
|
||||
|
||||
// We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
|
||||
// build our internal lld and use it as the default linker, by setting the `rust.lld` config
|
||||
// to true by default:
|
||||
// - on the `x86_64-unknown-linux-gnu` target
|
||||
// - on the `dev` and `nightly` channels
|
||||
// - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
|
||||
// we're also able to build the corresponding lld
|
||||
// - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
|
||||
// lld
|
||||
// - otherwise, we'd be using an external llvm, and lld would not necessarily available and
|
||||
// thus, disabled
|
||||
// - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
|
||||
// when the config sets `rust.lld = false`
|
||||
if self.build.triple == "x86_64-unknown-linux-gnu"
|
||||
&& self.hosts == [self.build]
|
||||
&& (self.channel == "dev" || self.channel == "nightly")
|
||||
{
|
||||
let no_llvm_config = self
|
||||
.target_config
|
||||
.get(&self.build)
|
||||
.is_some_and(|target_config| target_config.llvm_config.is_none());
|
||||
let enable_lld = self.llvm_from_ci || no_llvm_config;
|
||||
// Prefer the config setting in case an explicit opt-out is needed.
|
||||
self.lld_enabled = lld_enabled.unwrap_or(enable_lld);
|
||||
} else {
|
||||
set(&mut self.lld_enabled, lld_enabled);
|
||||
}
|
||||
|
||||
let default_std_features = BTreeSet::from([String::from("panic-unwind")]);
|
||||
self.rust_std_features = std_features.unwrap_or(default_std_features);
|
||||
|
||||
let default = debug == Some(true);
|
||||
self.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default);
|
||||
self.std_debug_assertions = std_debug_assertions.unwrap_or(self.rustc_debug_assertions);
|
||||
self.tools_debug_assertions = tools_debug_assertions.unwrap_or(self.rustc_debug_assertions);
|
||||
self.rust_overflow_checks = overflow_checks.unwrap_or(default);
|
||||
self.rust_overflow_checks_std = overflow_checks_std.unwrap_or(self.rust_overflow_checks);
|
||||
|
||||
self.rust_debug_logging = debug_logging.unwrap_or(self.rustc_debug_assertions);
|
||||
|
||||
let with_defaults = |debuginfo_level_specific: Option<_>| {
|
||||
debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
|
||||
DebuginfoLevel::Limited
|
||||
} else {
|
||||
DebuginfoLevel::None
|
||||
})
|
||||
};
|
||||
self.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
|
||||
self.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
|
||||
self.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
|
||||
self.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
|
||||
}
|
||||
}
|
||||
174
src/bootstrap/src/core/config/toml/target.rs
Normal file
174
src/bootstrap/src/core/config/toml/target.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
//! This module defines the structures and logic for handling target-specific configuration
|
||||
//! within the `bootstrap.toml` file. This allows you to customize build settings, tools,
|
||||
//! and flags for individual compilation targets.
|
||||
//!
|
||||
//! It includes:
|
||||
//!
|
||||
//! * [`TomlTarget`]: This struct directly mirrors the `[target.<triple>]` sections in your
|
||||
//! `bootstrap.toml`. It's used for deserializing raw TOML data for a specific target.
|
||||
//! * [`Target`]: This struct represents the processed and validated configuration for a
|
||||
//! build target, which is is stored in the main [`Config`] structure.
|
||||
//! * [`Config::apply_target_config`]: This method processes the `TomlTarget` data and
|
||||
//! applies it to the global [`Config`], ensuring proper path resolution, validation,
|
||||
//! and integration with other build settings.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
|
||||
use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool};
|
||||
use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit};
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of how each build target is configured.
|
||||
struct TomlTarget {
|
||||
cc: Option<String> = "cc",
|
||||
cxx: Option<String> = "cxx",
|
||||
ar: Option<String> = "ar",
|
||||
ranlib: Option<String> = "ranlib",
|
||||
default_linker: Option<PathBuf> = "default-linker",
|
||||
linker: Option<String> = "linker",
|
||||
split_debuginfo: Option<String> = "split-debuginfo",
|
||||
llvm_config: Option<String> = "llvm-config",
|
||||
llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
|
||||
llvm_filecheck: Option<String> = "llvm-filecheck",
|
||||
llvm_libunwind: Option<String> = "llvm-libunwind",
|
||||
sanitizers: Option<bool> = "sanitizers",
|
||||
profiler: Option<StringOrBool> = "profiler",
|
||||
rpath: Option<bool> = "rpath",
|
||||
crt_static: Option<bool> = "crt-static",
|
||||
musl_root: Option<String> = "musl-root",
|
||||
musl_libdir: Option<String> = "musl-libdir",
|
||||
wasi_root: Option<String> = "wasi-root",
|
||||
qemu_rootfs: Option<String> = "qemu-rootfs",
|
||||
no_std: Option<bool> = "no-std",
|
||||
codegen_backends: Option<Vec<String>> = "codegen-backends",
|
||||
runner: Option<String> = "runner",
|
||||
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
|
||||
jemalloc: Option<bool> = "jemalloc",
|
||||
}
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct Target {
|
||||
/// Some(path to llvm-config) if using an external LLVM.
|
||||
pub llvm_config: Option<PathBuf>,
|
||||
pub llvm_has_rust_patches: Option<bool>,
|
||||
/// Some(path to FileCheck) if one was specified.
|
||||
pub llvm_filecheck: Option<PathBuf>,
|
||||
pub llvm_libunwind: Option<LlvmLibunwind>,
|
||||
pub cc: Option<PathBuf>,
|
||||
pub cxx: Option<PathBuf>,
|
||||
pub ar: Option<PathBuf>,
|
||||
pub ranlib: Option<PathBuf>,
|
||||
pub default_linker: Option<PathBuf>,
|
||||
pub linker: Option<PathBuf>,
|
||||
pub split_debuginfo: Option<SplitDebuginfo>,
|
||||
pub sanitizers: Option<bool>,
|
||||
pub profiler: Option<StringOrBool>,
|
||||
pub rpath: Option<bool>,
|
||||
pub crt_static: Option<bool>,
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub musl_libdir: Option<PathBuf>,
|
||||
pub wasi_root: Option<PathBuf>,
|
||||
pub qemu_rootfs: Option<PathBuf>,
|
||||
pub runner: Option<String>,
|
||||
pub no_std: bool,
|
||||
pub codegen_backends: Option<Vec<String>>,
|
||||
pub optimized_compiler_builtins: Option<bool>,
|
||||
pub jemalloc: Option<bool>,
|
||||
}
|
||||
|
||||
impl Target {
|
||||
pub fn from_triple(triple: &str) -> Self {
|
||||
let mut target: Self = Default::default();
|
||||
if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
|
||||
target.no_std = true;
|
||||
}
|
||||
if triple.contains("emscripten") {
|
||||
target.runner = Some("node".into());
|
||||
}
|
||||
target
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn apply_target_config(&mut self, toml_target: Option<HashMap<String, TomlTarget>>) {
|
||||
if let Some(t) = toml_target {
|
||||
for (triple, cfg) in t {
|
||||
let mut target = Target::from_triple(&triple);
|
||||
|
||||
if let Some(ref s) = cfg.llvm_config {
|
||||
if self.download_rustc_commit.is_some() && triple == *self.build.triple {
|
||||
panic!(
|
||||
"setting llvm_config for the host is incompatible with download-rustc"
|
||||
);
|
||||
}
|
||||
target.llvm_config = Some(self.src.join(s));
|
||||
}
|
||||
if let Some(patches) = cfg.llvm_has_rust_patches {
|
||||
assert!(
|
||||
self.submodules == Some(false) || cfg.llvm_config.is_some(),
|
||||
"use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided"
|
||||
);
|
||||
target.llvm_has_rust_patches = Some(patches);
|
||||
}
|
||||
if let Some(ref s) = cfg.llvm_filecheck {
|
||||
target.llvm_filecheck = Some(self.src.join(s));
|
||||
}
|
||||
target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| {
|
||||
v.parse().unwrap_or_else(|_| {
|
||||
panic!("failed to parse target.{triple}.llvm-libunwind")
|
||||
})
|
||||
});
|
||||
if let Some(s) = cfg.no_std {
|
||||
target.no_std = s;
|
||||
}
|
||||
target.cc = cfg.cc.map(PathBuf::from);
|
||||
target.cxx = cfg.cxx.map(PathBuf::from);
|
||||
target.ar = cfg.ar.map(PathBuf::from);
|
||||
target.ranlib = cfg.ranlib.map(PathBuf::from);
|
||||
target.linker = cfg.linker.map(PathBuf::from);
|
||||
target.crt_static = cfg.crt_static;
|
||||
target.musl_root = cfg.musl_root.map(PathBuf::from);
|
||||
target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
|
||||
target.wasi_root = cfg.wasi_root.map(PathBuf::from);
|
||||
target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
|
||||
target.runner = cfg.runner;
|
||||
target.sanitizers = cfg.sanitizers;
|
||||
target.profiler = cfg.profiler;
|
||||
target.rpath = cfg.rpath;
|
||||
target.optimized_compiler_builtins = cfg.optimized_compiler_builtins;
|
||||
target.jemalloc = cfg.jemalloc;
|
||||
|
||||
if let Some(ref backends) = cfg.codegen_backends {
|
||||
let available_backends = ["llvm", "cranelift", "gcc"];
|
||||
|
||||
target.codegen_backends = Some(backends.iter().map(|s| {
|
||||
if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
|
||||
if available_backends.contains(&backend) {
|
||||
panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
|
||||
} else {
|
||||
println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
|
||||
Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
|
||||
In this case, it would be referred to as '{backend}'.");
|
||||
}
|
||||
}
|
||||
|
||||
s.clone()
|
||||
}).collect());
|
||||
}
|
||||
|
||||
target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| {
|
||||
v.parse().unwrap_or_else(|_| {
|
||||
panic!("invalid value for target.{triple}.split-debuginfo")
|
||||
})
|
||||
});
|
||||
|
||||
self.target_config.insert(TargetSelection::from_user(&triple), target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue