Skip to content

Commit 0d7864a

Browse files
committed
feat(config): Introduce dedicated 'toml' submodule for raw config structures
This commit introduces a new `toml` submodule within the `src/bootstrap/config` directory, fundamentally restructuring how `bootstrap.toml`'s on-disk representation is handled. Key changes introduced in this commit: 1. Dedicated `toml` Module: A new `src/bootstrap/config/toml` directory is created. This module is now solely responsible for defining the Rust types that directly mirror the structure of the `bootstrap.toml` file. These types serve as the initial layer for `serde` deserialization before further processing and merging into the final `Config`. 2. Field-Based Segregation within `toml`: To further enhance clarity and ownership, the raw TOML configuration types are segregated into individual files corresponding to the top-level sections of `bootstrap.toml`: * `build.rs`: For `[build]` related TOML structures. * `change_id.rs`: For the `change-id` field. * `dist.rs`: For `[dist]` options. * `gcc.rs`: For `[gcc]` options. * `install.rs`: For `[install]` options. * `llvm.rs`: For `[llvm]` options. * `rust.rs`: For `[rust]` options. * `target.rs`: For `[target.<triple>]` options. 3. Encapsulated Core Utilities: The `Merge` trait (now defined in `toml/merge.rs`) and the `define_config!` macro (in `toml/macros.rs`) have been moved into dedicated modules within the `toml` subdirectory. As these utilities are integral to how the raw TOML structures are processed (deserialized, merged, and constructed), centralizing them here enhances the self-contained nature of the `toml` module. A `common.rs` is also introduced within `toml` for types shared among its sub-modules.
1 parent 26b95f0 commit 0d7864a

File tree

20 files changed

+1118
-1047
lines changed

20 files changed

+1118
-1047
lines changed

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ use tracing::{instrument, span};
2323

2424
use crate::core::build_steps::llvm;
2525
use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
26-
use crate::core::config::Target;
2726
use crate::core::config::flags::Color;
2827
pub use crate::core::config::flags::Subcommand;
2928
use crate::core::config::parsing::check_incompatible_options_for_ci_rustc;
30-
use crate::core::config::toml::*;
31-
use crate::core::config::types::{
32-
DebuginfoLevel, DryRun, GccCiMode, LldMode, LlvmLibunwind, RustOptimize, RustcLto,
33-
SplitDebuginfo, StringOrBool,
29+
use crate::core::config::toml::change_id::{ChangeId, ChangeIdWrapper};
30+
use crate::core::config::toml::common::{
31+
DebuginfoLevel, LlvmLibunwind, SplitDebuginfo, StringOrBool,
3432
};
33+
use crate::core::config::toml::rust::{LldMode, RustOptimize};
34+
use crate::core::config::toml::target::Target;
35+
use crate::core::config::toml::*;
36+
use crate::core::config::types::{DryRun, GccCiMode, RustcLto};
3537
use crate::core::download::is_download_ci_available;
3638
use crate::utils::channel;
3739
use crate::{Command, Flags, GitInfo, OnceLock, TargetSelection, helpers, output, t};

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use tracing::instrument;
1212
use crate::core::build_steps::perf::PerfArgs;
1313
use crate::core::build_steps::setup::Profile;
1414
use crate::core::builder::{Builder, Kind};
15-
use crate::core::config::types::TargetSelectionList;
16-
use crate::core::config::{Config, target_selection_list};
15+
use crate::core::config::Config;
16+
use crate::core::config::target_selection::{TargetSelectionList, target_selection_list};
1717
use crate::{Build, DocTests};
1818

1919
#[derive(Copy, Clone, Default, Debug, ValueEnum)]

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
mod config;
33
pub mod flags;
44
pub mod parsing;
5+
pub mod target_selection;
56
#[cfg(test)]
67
mod tests;
78
pub mod toml;
89
pub mod types;
910

1011
pub use config::*;
11-
pub use toml::ChangeId;
12+
pub use target_selection::TargetSelection;
13+
pub use toml::change_id::ChangeId;
14+
pub use toml::common::*;
15+
pub use toml::rust::LldMode;
16+
pub use toml::target::Target;
1217
pub use types::*;

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,22 @@ use serde::Deserialize;
1818
use tracing::{instrument, span};
1919

2020
use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
21-
use crate::core::config::Target;
2221
pub use crate::core::config::flags::Subcommand;
2322
use crate::core::config::flags::{Flags, Warnings};
24-
use crate::core::config::toml::{Merge, ReplaceOpt, *};
25-
use crate::core::config::types::{
26-
DebuginfoLevel, DryRun, GccCiMode, LldMode, RustOptimize, RustcLto, StringOrBool,
27-
TargetSelectionList,
28-
};
23+
use crate::core::config::target_selection::TargetSelectionList;
24+
use crate::core::config::toml::TomlConfig;
25+
use crate::core::config::toml::build::Build;
26+
use crate::core::config::toml::common::{DebuginfoLevel, ReplaceOpt, StringOrBool};
27+
use crate::core::config::toml::dist::Dist;
28+
use crate::core::config::toml::install::Install;
29+
use crate::core::config::toml::llvm::Llvm;
30+
use crate::core::config::toml::merge::Merge;
31+
use crate::core::config::toml::rust::{LldMode, Rust, RustOptimize};
32+
use crate::core::config::toml::target::Target;
33+
use crate::core::config::{GccCiMode, RustcLto};
2934
use crate::utils::channel::GitInfo;
3035
use crate::utils::helpers::{self, exe, t};
31-
use crate::{Config, TargetSelection, check_ci_llvm};
36+
use crate::{Config, DryRun, TargetSelection, check_ci_llvm};
3237

3338
/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options.
3439
/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use std::fmt;
2+
3+
use crate::core::config::toml::common::SplitDebuginfo;
4+
use crate::utils::cache::{INTERNER, Interned};
5+
use crate::{Path, env};
6+
7+
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
8+
// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy.
9+
// Making !Copy is highly nontrivial!
10+
pub struct TargetSelection {
11+
pub triple: Interned<String>,
12+
pub file: Option<Interned<String>>,
13+
pub synthetic: bool,
14+
}
15+
16+
/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
17+
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
18+
pub struct TargetSelectionList(pub Vec<TargetSelection>);
19+
20+
pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> {
21+
Ok(TargetSelectionList(
22+
s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(),
23+
))
24+
}
25+
26+
impl TargetSelection {
27+
pub fn from_user(selection: &str) -> Self {
28+
let path = Path::new(selection);
29+
30+
let (triple, file) = if path.exists() {
31+
let triple = path
32+
.file_stem()
33+
.expect("Target specification file has no file stem")
34+
.to_str()
35+
.expect("Target specification file stem is not UTF-8");
36+
37+
(triple, Some(selection))
38+
} else {
39+
(selection, None)
40+
};
41+
42+
let triple = INTERNER.intern_str(triple);
43+
let file = file.map(|f| INTERNER.intern_str(f));
44+
45+
Self { triple, file, synthetic: false }
46+
}
47+
48+
pub fn create_synthetic(triple: &str, file: &str) -> Self {
49+
Self {
50+
triple: INTERNER.intern_str(triple),
51+
file: Some(INTERNER.intern_str(file)),
52+
synthetic: true,
53+
}
54+
}
55+
56+
pub fn rustc_target_arg(&self) -> &str {
57+
self.file.as_ref().unwrap_or(&self.triple)
58+
}
59+
60+
pub fn contains(&self, needle: &str) -> bool {
61+
self.triple.contains(needle)
62+
}
63+
64+
pub fn starts_with(&self, needle: &str) -> bool {
65+
self.triple.starts_with(needle)
66+
}
67+
68+
pub fn ends_with(&self, needle: &str) -> bool {
69+
self.triple.ends_with(needle)
70+
}
71+
72+
// See src/bootstrap/synthetic_targets.rs
73+
pub fn is_synthetic(&self) -> bool {
74+
self.synthetic
75+
}
76+
77+
pub fn is_msvc(&self) -> bool {
78+
self.contains("msvc")
79+
}
80+
81+
pub fn is_windows(&self) -> bool {
82+
self.contains("windows")
83+
}
84+
85+
pub fn is_windows_gnu(&self) -> bool {
86+
self.ends_with("windows-gnu")
87+
}
88+
89+
pub fn is_cygwin(&self) -> bool {
90+
self.is_windows() &&
91+
// ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html
92+
env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin"))
93+
}
94+
95+
pub fn needs_crt_begin_end(&self) -> bool {
96+
self.contains("musl") && !self.contains("unikraft")
97+
}
98+
99+
/// Path to the file defining the custom target, if any.
100+
pub fn filepath(&self) -> Option<&Path> {
101+
self.file.as_ref().map(Path::new)
102+
}
103+
}
104+
105+
impl fmt::Display for TargetSelection {
106+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107+
write!(f, "{}", self.triple)?;
108+
if let Some(file) = self.file {
109+
write!(f, "({file})")?;
110+
}
111+
Ok(())
112+
}
113+
}
114+
115+
impl fmt::Debug for TargetSelection {
116+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117+
write!(f, "{self}")
118+
}
119+
}
120+
121+
impl PartialEq<&str> for TargetSelection {
122+
fn eq(&self, other: &&str) -> bool {
123+
self.triple == *other
124+
}
125+
}
126+
127+
// Targets are often used as directory names throughout bootstrap.
128+
// This impl makes it more ergonomics to use them as such.
129+
impl AsRef<Path> for TargetSelection {
130+
fn as_ref(&self) -> &Path {
131+
self.triple.as_ref()
132+
}
133+
}
134+
135+
impl SplitDebuginfo {
136+
/// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
137+
/// `rust.split-debuginfo` in `bootstrap.example.toml`.
138+
pub fn default_for_platform(target: TargetSelection) -> Self {
139+
if target.contains("apple") {
140+
SplitDebuginfo::Unpacked
141+
} else if target.is_windows() {
142+
SplitDebuginfo::Packed
143+
} else {
144+
SplitDebuginfo::Off
145+
}
146+
}
147+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use clap::CommandFactory;
1010
use serde::Deserialize;
1111

1212
use super::flags::Flags;
13-
use super::toml::ChangeIdWrapper;
13+
use super::toml::change_id::ChangeIdWrapper;
1414
use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
1515
use crate::ChangeId;
1616
use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};

0 commit comments

Comments
 (0)