//! This module implements parsing `config.toml` configuration files to tweak
//! how the build runs.
+#[cfg(test)]
+mod tests;
+
use std::cell::{Cell, RefCell};
use std::cmp;
use std::collections::{HashMap, HashSet};
use crate::builder::TaskPath;
use crate::cache::{Interned, INTERNER};
+use crate::cc_detect::{ndk_compiler, Language};
use crate::channel::{self, GitInfo};
pub use crate::flags::Subcommand;
use crate::flags::{Color, Flags};
pub npm: Option<PathBuf>,
pub gdb: Option<PathBuf>,
pub python: Option<PathBuf>,
+ pub reuse: Option<PathBuf>,
pub cargo_native_static: bool,
pub configure_args: Vec<String>,
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",
}
}
-#[derive(Deserialize)]
+#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum StringOrBool {
String(String),
}
pub fn parse(args: &[String]) -> Config {
+ #[cfg(test)]
+ let get_toml = |_: &_| TomlConfig::default();
+ #[cfg(not(test))]
+ let get_toml = |file: &Path| {
+ 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.
+ match toml::from_str(&contents)
+ .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+ {
+ Ok(table) => table,
+ Err(err) => {
+ eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err);
+ crate::detail_exit(2);
+ }
+ }
+ };
+
+ Self::parse_inner(args, get_toml)
+ }
+
+ fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig) -> Config {
let flags = Flags::parse(&args);
let mut config = Config::default_opts();
config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
- #[cfg(test)]
- let get_toml = |_| TomlConfig::default();
- #[cfg(not(test))]
- let get_toml = |file: &Path| {
- 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.
- match toml::from_str(&contents)
- .and_then(|table: toml::Value| TomlConfig::deserialize(table))
- {
- Ok(table) => table,
- Err(err) => {
- eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err);
- crate::detail_exit(2);
- }
- }
- };
-
// Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
let toml_path = flags
.config
config.npm = build.npm.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
config.python = build.python.map(PathBuf::from);
+ config.reuse = build.reuse.map(PathBuf::from);
config.submodules = build.submodules;
set(&mut config.low_priority, build.low_priority);
set(&mut config.compiler_docs, build.compiler_docs);
let mut optimize = None;
let mut ignore_git = None;
+ if let Some(rust) = toml.rust {
+ debug = rust.debug;
+ debug_assertions = rust.debug_assertions;
+ debug_assertions_std = rust.debug_assertions_std;
+ overflow_checks = rust.overflow_checks;
+ overflow_checks_std = rust.overflow_checks_std;
+ debug_logging = rust.debug_logging;
+ debuginfo_level = rust.debuginfo_level;
+ debuginfo_level_rustc = rust.debuginfo_level_rustc;
+ debuginfo_level_std = rust.debuginfo_level_std;
+ debuginfo_level_tools = rust.debuginfo_level_tools;
+ debuginfo_level_tests = rust.debuginfo_level_tests;
+ config.rust_split_debuginfo = rust
+ .split_debuginfo
+ .as_deref()
+ .map(SplitDebuginfo::from_str)
+ .map(|v| v.expect("invalid value for rust.split_debuginfo"))
+ .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
+ optimize = rust.optimize;
+ ignore_git = rust.ignore_git;
+ config.rust_new_symbol_mangling = rust.new_symbol_mangling;
+ set(&mut config.rust_optimize_tests, rust.optimize_tests);
+ set(&mut config.codegen_tests, rust.codegen_tests);
+ set(&mut config.rust_rpath, rust.rpath);
+ set(&mut config.jemalloc, rust.jemalloc);
+ set(&mut config.test_compare_mode, rust.test_compare_mode);
+ set(&mut config.backtrace, rust.backtrace);
+ set(&mut config.channel, rust.channel);
+ config.description = rust.description;
+ set(&mut config.rust_dist_src, rust.dist_src);
+ set(&mut config.verbose_tests, rust.verbose_tests);
+ // in the case "false" is set explicitly, do not overwrite the command line args
+ if let Some(true) = rust.incremental {
+ config.incremental = true;
+ }
+ set(&mut config.use_lld, rust.use_lld);
+ set(&mut config.lld_enabled, rust.lld);
+ set(&mut config.llvm_tools_enabled, rust.llvm_tools);
+ config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
+ config.rustc_default_linker = rust.default_linker;
+ config.musl_root = rust.musl_root.map(PathBuf::from);
+ config.save_toolstates = rust.save_toolstates.map(PathBuf::from);
+ set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
+ set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
+ set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
+ config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
+ set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
+ set(&mut config.control_flow_guard, rust.control_flow_guard);
+ config.llvm_libunwind_default = rust
+ .llvm_libunwind
+ .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
+
+ if let Some(ref backends) = rust.codegen_backends {
+ config.rust_codegen_backends =
+ backends.iter().map(|s| INTERNER.intern_str(s)).collect();
+ }
+
+ config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
+ config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
+ config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
+ config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
+ config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
+
+ config.rust_lto = rust
+ .lto
+ .as_deref()
+ .map(|value| RustcLto::from_str(value).unwrap())
+ .unwrap_or_default();
+ } else {
+ config.rust_profile_use = flags.rust_profile_use;
+ config.rust_profile_generate = flags.rust_profile_generate;
+ }
+
if let Some(llvm) = toml.llvm {
match llvm.ccache {
Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()),
config.llvm_polly = llvm.polly.unwrap_or(false);
config.llvm_clang = llvm.clang.unwrap_or(false);
config.llvm_build_config = llvm.build_config.clone().unwrap_or(Default::default());
+
+ let asserts = llvm_assertions.unwrap_or(false);
config.llvm_from_ci = match llvm.download_ci_llvm {
Some(StringOrBool::String(s)) => {
assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
- crate::native::is_ci_llvm_available(&config, llvm_assertions.unwrap_or(false))
+ crate::native::is_ci_llvm_available(&config, asserts)
}
Some(StringOrBool::Bool(b)) => b,
- None => false,
+ None => {
+ config.channel == "dev" && crate::native::is_ci_llvm_available(&config, asserts)
+ }
};
if config.llvm_from_ci {
// the link step) with each stage.
config.llvm_link_shared.set(Some(true));
}
- }
-
- if let Some(rust) = toml.rust {
- debug = rust.debug;
- debug_assertions = rust.debug_assertions;
- debug_assertions_std = rust.debug_assertions_std;
- overflow_checks = rust.overflow_checks;
- overflow_checks_std = rust.overflow_checks_std;
- debug_logging = rust.debug_logging;
- debuginfo_level = rust.debuginfo_level;
- debuginfo_level_rustc = rust.debuginfo_level_rustc;
- debuginfo_level_std = rust.debuginfo_level_std;
- debuginfo_level_tools = rust.debuginfo_level_tools;
- debuginfo_level_tests = rust.debuginfo_level_tests;
- config.rust_split_debuginfo = rust
- .split_debuginfo
- .as_deref()
- .map(SplitDebuginfo::from_str)
- .map(|v| v.expect("invalid value for rust.split_debuginfo"))
- .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
- optimize = rust.optimize;
- ignore_git = rust.ignore_git;
- config.rust_new_symbol_mangling = rust.new_symbol_mangling;
- set(&mut config.rust_optimize_tests, rust.optimize_tests);
- set(&mut config.codegen_tests, rust.codegen_tests);
- set(&mut config.rust_rpath, rust.rpath);
- set(&mut config.jemalloc, rust.jemalloc);
- set(&mut config.test_compare_mode, rust.test_compare_mode);
- set(&mut config.backtrace, rust.backtrace);
- set(&mut config.channel, rust.channel);
- config.description = rust.description;
- set(&mut config.rust_dist_src, rust.dist_src);
- set(&mut config.verbose_tests, rust.verbose_tests);
- // in the case "false" is set explicitly, do not overwrite the command line args
- if let Some(true) = rust.incremental {
- config.incremental = true;
- }
- set(&mut config.use_lld, rust.use_lld);
- set(&mut config.lld_enabled, rust.lld);
- set(&mut config.llvm_tools_enabled, rust.llvm_tools);
- config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
- config.rustc_default_linker = rust.default_linker;
- config.musl_root = rust.musl_root.map(PathBuf::from);
- config.save_toolstates = rust.save_toolstates.map(PathBuf::from);
- set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
- set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
- set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
- config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
- set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
- set(&mut config.control_flow_guard, rust.control_flow_guard);
- config.llvm_libunwind_default = rust
- .llvm_libunwind
- .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
-
- if let Some(ref backends) = rust.codegen_backends {
- config.rust_codegen_backends =
- backends.iter().map(|s| INTERNER.intern_str(s)).collect();
- }
-
- config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
- config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
- config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
- config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
- config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
-
- config.rust_lto = rust
- .lto
- .as_deref()
- .map(|value| RustcLto::from_str(value).unwrap())
- .unwrap_or_default();
} else {
- config.rust_profile_use = flags.rust_profile_use;
- config.rust_profile_generate = flags.rust_profile_generate;
+ config.llvm_from_ci =
+ config.channel == "dev" && crate::native::is_ci_llvm_available(&config, false);
}
if let Some(t) = toml.target {
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.cc = cfg.cc.map(PathBuf::from).or_else(|| {
+ target.ndk.as_ref().map(|ndk| ndk_compiler(Language::C, &triple, ndk))
+ });
+ target.cxx = cfg.cxx.map(PathBuf::from).or_else(|| {
+ target.ndk.as_ref().map(|ndk| ndk_compiler(Language::CPlusPlus, &triple, ndk))
+ });
target.ar = cfg.ar.map(PathBuf::from);
target.ranlib = cfg.ranlib.map(PathBuf::from);
target.linker = cfg.linker.map(PathBuf::from);
/// Return whether we will use a downloaded, pre-compiled version of rustc, or just build from source.
pub(crate) fn download_rustc(&self) -> bool {
- static DOWNLOAD_RUSTC: OnceCell<bool> = OnceCell::new();
+ self.download_rustc_commit().is_some()
+ }
+
+ pub(crate) fn download_rustc_commit(&self) -> Option<&'static str> {
+ static DOWNLOAD_RUSTC: OnceCell<Option<String>> = OnceCell::new();
if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() {
// avoid trying to actually download the commit
- return false;
+ return None;
}
- *DOWNLOAD_RUSTC.get_or_init(|| match &self.download_rustc_commit {
- None => false,
- Some(commit) => {
- self.download_ci_rustc(commit);
- true
- }
- })
+ DOWNLOAD_RUSTC
+ .get_or_init(|| match &self.download_rustc_commit {
+ None => None,
+ Some(commit) => {
+ self.download_ci_rustc(commit);
+ Some(commit.clone())
+ }
+ })
+ .as_deref()
}
pub(crate) fn initial_rustfmt(&self) -> Option<PathBuf> {