@@ -36,6 +36,14 @@ macro_rules! check_ci_llvm {
36
36
} ;
37
37
}
38
38
39
+ /// This file is embedded in the overlay directory of the tarball sources. It is
40
+ /// useful in scenarios where developers want to see how the tarball sources were
41
+ /// generated.
42
+ ///
43
+ /// We also use this file to compare the host's config.toml against the CI rustc builder
44
+ /// configuration to detect any incompatible options.
45
+ pub ( crate ) const BUILDER_CONFIG_FILENAME : & str = "builder-config" ;
46
+
39
47
#[ derive( Clone , Default ) ]
40
48
pub enum DryRun {
41
49
/// This isn't a dry run.
@@ -47,7 +55,7 @@ pub enum DryRun {
47
55
UserSelected ,
48
56
}
49
57
50
- #[ derive( Copy , Clone , Default , PartialEq , Eq ) ]
58
+ #[ derive( Copy , Clone , Default , Debug , Eq , PartialEq ) ]
51
59
pub enum DebuginfoLevel {
52
60
#[ default]
53
61
None ,
@@ -117,7 +125,7 @@ impl Display for DebuginfoLevel {
117
125
/// 2) MSVC
118
126
/// - Self-contained: `-Clinker=<path to rust-lld>`
119
127
/// - External: `-Clinker=lld`
120
- #[ derive( Default , Copy , Clone ) ]
128
+ #[ derive( Copy , Clone , Default , Debug , PartialEq ) ]
121
129
pub enum LldMode {
122
130
/// Do not use LLD
123
131
#[ default]
@@ -1203,40 +1211,42 @@ impl Config {
1203
1211
}
1204
1212
}
1205
1213
1206
- pub fn parse ( flags : Flags ) -> Config {
1207
- #[ cfg( test) ]
1208
- fn get_toml ( _: & Path ) -> TomlConfig {
1209
- TomlConfig :: default ( )
1210
- }
1214
+ #[ cfg( test) ]
1215
+ fn get_toml ( _: & Path ) -> Result < TomlConfig , toml:: de:: Error > {
1216
+ Ok ( TomlConfig :: default ( ) )
1217
+ }
1211
1218
1212
- #[ cfg( not( test) ) ]
1213
- fn get_toml ( file : & Path ) -> TomlConfig {
1214
- let contents =
1215
- t ! ( fs:: read_to_string( file) , format!( "config file {} not found" , file. display( ) ) ) ;
1216
- // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
1217
- // TomlConfig and sub types to be monomorphized 5x by toml.
1218
- toml:: from_str ( & contents)
1219
- . and_then ( |table : toml:: Value | TomlConfig :: deserialize ( table) )
1220
- . unwrap_or_else ( |err | {
1221
- if let Ok ( Some ( changes) ) = toml:: from_str ( & contents)
1222
- . and_then ( |table : toml:: Value | ChangeIdWrapper :: deserialize ( table) ) . map ( |change_id| change_id . inner . map ( crate :: find_recent_config_change_ids ) )
1223
- {
1224
- if !changes . is_empty ( ) {
1225
- println ! (
1226
- "WARNING: There have been changes to x.py since you last updated: \n {}" ,
1227
- crate :: human_readable_changes ( & changes)
1228
- ) ;
1229
- }
1219
+ #[ cfg( not( test) ) ]
1220
+ fn get_toml ( file : & Path ) -> Result < TomlConfig , toml :: de :: Error > {
1221
+ let contents =
1222
+ t ! ( fs:: read_to_string( file) , format!( "config file {} not found" , file. display( ) ) ) ;
1223
+ // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
1224
+ // TomlConfig and sub types to be monomorphized 5x by toml.
1225
+ toml:: from_str ( & contents)
1226
+ . and_then ( |table : toml:: Value | TomlConfig :: deserialize ( table) )
1227
+ . inspect_err ( |_ | {
1228
+ if let Ok ( Some ( changes) ) = toml:: from_str ( & contents)
1229
+ . and_then ( |table : toml:: Value | ChangeIdWrapper :: deserialize ( table) )
1230
+ . map ( |change_id| change_id . inner . map ( crate :: find_recent_config_change_ids ) )
1231
+ {
1232
+ if !changes . is_empty ( ) {
1233
+ println ! (
1234
+ "WARNING: There have been changes to x.py since you last updated: \n {}" ,
1235
+ crate :: human_readable_changes ( & changes )
1236
+ ) ;
1230
1237
}
1238
+ }
1239
+ } )
1240
+ }
1231
1241
1232
- eprintln ! ( "failed to parse TOML configuration '{}': {err}" , file. display( ) ) ;
1233
- exit ! ( 2 ) ;
1234
- } )
1235
- }
1236
- Self :: parse_inner ( flags, get_toml)
1242
+ pub fn parse ( flags : Flags ) -> Config {
1243
+ Self :: parse_inner ( flags, Self :: get_toml)
1237
1244
}
1238
1245
1239
- pub ( crate ) fn parse_inner ( mut flags : Flags , get_toml : impl Fn ( & Path ) -> TomlConfig ) -> Config {
1246
+ pub ( crate ) fn parse_inner (
1247
+ mut flags : Flags ,
1248
+ get_toml : impl Fn ( & Path ) -> Result < TomlConfig , toml:: de:: Error > ,
1249
+ ) -> Config {
1240
1250
let mut config = Config :: default_opts ( ) ;
1241
1251
1242
1252
// Set flags.
@@ -1344,7 +1354,10 @@ impl Config {
1344
1354
} else {
1345
1355
toml_path. clone ( )
1346
1356
} ) ;
1347
- get_toml ( & toml_path)
1357
+ get_toml ( & toml_path) . unwrap_or_else ( |e| {
1358
+ eprintln ! ( "ERROR: Failed to parse '{}': {e}" , toml_path. display( ) ) ;
1359
+ exit ! ( 2 ) ;
1360
+ } )
1348
1361
} else {
1349
1362
config. config = None ;
1350
1363
TomlConfig :: default ( )
@@ -1375,7 +1388,13 @@ impl Config {
1375
1388
include_path. push ( "bootstrap" ) ;
1376
1389
include_path. push ( "defaults" ) ;
1377
1390
include_path. push ( format ! ( "config.{include}.toml" ) ) ;
1378
- let included_toml = get_toml ( & include_path) ;
1391
+ let included_toml = get_toml ( & include_path) . unwrap_or_else ( |e| {
1392
+ eprintln ! (
1393
+ "ERROR: Failed to parse default config profile at '{}': {e}" ,
1394
+ include_path. display( )
1395
+ ) ;
1396
+ exit ! ( 2 ) ;
1397
+ } ) ;
1379
1398
toml. merge ( included_toml, ReplaceOpt :: IgnoreDuplicate ) ;
1380
1399
}
1381
1400
@@ -1591,24 +1610,6 @@ impl Config {
1591
1610
let mut is_user_configured_rust_channel = false ;
1592
1611
1593
1612
if let Some ( rust) = toml. rust {
1594
- if let Some ( commit) = config. download_ci_rustc_commit ( rust. download_rustc . clone ( ) ) {
1595
- // Primarily used by CI runners to avoid handling download-rustc incompatible
1596
- // options one by one on shell scripts.
1597
- let disable_ci_rustc_if_incompatible =
1598
- env:: var_os ( "DISABLE_CI_RUSTC_IF_INCOMPATIBLE" )
1599
- . is_some_and ( |s| s == "1" || s == "true" ) ;
1600
-
1601
- if let Err ( e) = check_incompatible_options_for_ci_rustc ( & rust) {
1602
- if disable_ci_rustc_if_incompatible {
1603
- config. download_rustc_commit = None ;
1604
- } else {
1605
- panic ! ( "{}" , e) ;
1606
- }
1607
- } else {
1608
- config. download_rustc_commit = Some ( commit) ;
1609
- }
1610
- }
1611
-
1612
1613
let Rust {
1613
1614
optimize : optimize_toml,
1614
1615
debug : debug_toml,
@@ -1656,7 +1657,7 @@ impl Config {
1656
1657
new_symbol_mangling,
1657
1658
profile_generate,
1658
1659
profile_use,
1659
- download_rustc : _ ,
1660
+ download_rustc,
1660
1661
lto,
1661
1662
validate_mir_opts,
1662
1663
frame_pointers,
@@ -1668,6 +1669,8 @@ impl Config {
1668
1669
is_user_configured_rust_channel = channel. is_some ( ) ;
1669
1670
set ( & mut config. channel , channel. clone ( ) ) ;
1670
1671
1672
+ config. download_rustc_commit = config. download_ci_rustc_commit ( download_rustc) ;
1673
+
1671
1674
debug = debug_toml;
1672
1675
debug_assertions = debug_assertions_toml;
1673
1676
debug_assertions_std = debug_assertions_std_toml;
@@ -2345,6 +2348,45 @@ impl Config {
2345
2348
None => None ,
2346
2349
Some ( commit) => {
2347
2350
self . download_ci_rustc ( commit) ;
2351
+
2352
+ if let Some ( config_path) = & self . config {
2353
+ let builder_config_path =
2354
+ self . out . join ( self . build . triple ) . join ( "ci-rustc" ) . join ( BUILDER_CONFIG_FILENAME ) ;
2355
+
2356
+ let ci_config_toml = match Self :: get_toml ( & builder_config_path) {
2357
+ Ok ( ci_config_toml) => ci_config_toml,
2358
+ Err ( e) if e. to_string ( ) . contains ( "unknown field" ) => {
2359
+ println ! ( "WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled." ) ;
2360
+ println ! ( "HELP: Consider rebasing to a newer commit if available." ) ;
2361
+ return None ;
2362
+ } ,
2363
+ Err ( e) => {
2364
+ eprintln ! ( "ERROR: Failed to parse CI rustc config at '{}': {e}" , builder_config_path. display( ) ) ;
2365
+ exit ! ( 2 ) ;
2366
+ } ,
2367
+ } ;
2368
+
2369
+ let current_config_toml = Self :: get_toml ( config_path) . unwrap ( ) ;
2370
+
2371
+ // Check the config compatibility
2372
+ // FIXME: this doesn't cover `--set` flags yet.
2373
+ let res = check_incompatible_options_for_ci_rustc (
2374
+ current_config_toml,
2375
+ ci_config_toml,
2376
+ ) ;
2377
+
2378
+ let disable_ci_rustc_if_incompatible =
2379
+ env:: var_os ( "DISABLE_CI_RUSTC_IF_INCOMPATIBLE" )
2380
+ . is_some_and ( |s| s == "1" || s == "true" ) ;
2381
+
2382
+ if disable_ci_rustc_if_incompatible && res. is_err ( ) {
2383
+ println ! ( "WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env." ) ;
2384
+ return None ;
2385
+ }
2386
+
2387
+ res. unwrap ( ) ;
2388
+ }
2389
+
2348
2390
Some ( commit. clone ( ) )
2349
2391
}
2350
2392
} )
@@ -2662,31 +2704,52 @@ impl Config {
2662
2704
}
2663
2705
}
2664
2706
2665
- /// Checks the CI rustc incompatible options by destructuring the `Rust` instance
2666
- /// and makes sure that no rust options from config.toml are missed.
2667
- fn check_incompatible_options_for_ci_rustc ( rust : & Rust ) -> Result < ( ) , String > {
2707
+ /// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options.
2708
+ /// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing.
2709
+ fn check_incompatible_options_for_ci_rustc (
2710
+ current_config_toml : TomlConfig ,
2711
+ ci_config_toml : TomlConfig ,
2712
+ ) -> Result < ( ) , String > {
2668
2713
macro_rules! err {
2669
- ( $name: expr) => {
2670
- if $name. is_some( ) {
2671
- return Err ( format!(
2672
- "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`." ,
2673
- stringify!( $name) . replace( "_" , "-" )
2674
- ) ) ;
2675
- }
2714
+ ( $current: expr, $expected: expr) => {
2715
+ if let Some ( current) = & $current {
2716
+ if Some ( current) != $expected. as_ref( ) {
2717
+ return Err ( format!(
2718
+ "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`. \
2719
+ Current value: {:?}, Expected value(s): {}{:?}",
2720
+ stringify!( $expected) . replace( "_" , "-" ) ,
2721
+ $current,
2722
+ if $expected. is_some( ) { "None/" } else { "" } ,
2723
+ $expected,
2724
+ ) ) ;
2725
+ } ;
2726
+ } ;
2676
2727
} ;
2677
2728
}
2678
2729
2679
2730
macro_rules! warn {
2680
- ( $name: expr) => {
2681
- if $name. is_some( ) {
2682
- println!(
2683
- "WARNING: `rust.{}` has no effect with `rust.download-rustc`." ,
2684
- stringify!( $name) . replace( "_" , "-" )
2685
- ) ;
2686
- }
2731
+ ( $current: expr, $expected: expr) => {
2732
+ if let Some ( current) = & $current {
2733
+ if Some ( current) != $expected. as_ref( ) {
2734
+ println!(
2735
+ "WARNING: `rust.{}` has no effect with `rust.download-rustc`. \
2736
+ Current value: {:?}, Expected value(s): {}{:?}",
2737
+ stringify!( $expected) . replace( "_" , "-" ) ,
2738
+ $current,
2739
+ if $expected. is_some( ) { "None/" } else { "" } ,
2740
+ $expected,
2741
+ ) ;
2742
+ } ;
2743
+ } ;
2687
2744
} ;
2688
2745
}
2689
2746
2747
+ let ( Some ( current_rust_config) , Some ( ci_rust_config) ) =
2748
+ ( current_config_toml. rust , ci_config_toml. rust )
2749
+ else {
2750
+ return Ok ( ( ) ) ;
2751
+ } ;
2752
+
2690
2753
let Rust {
2691
2754
// Following options are the CI rustc incompatible ones.
2692
2755
optimize,
@@ -2744,30 +2807,31 @@ fn check_incompatible_options_for_ci_rustc(rust: &Rust) -> Result<(), String> {
2744
2807
download_rustc : _,
2745
2808
validate_mir_opts : _,
2746
2809
frame_pointers : _,
2747
- } = rust ;
2810
+ } = ci_rust_config ;
2748
2811
2749
2812
// There are two kinds of checks for CI rustc incompatible options:
2750
2813
// 1. Checking an option that may change the compiler behaviour/output.
2751
2814
// 2. Checking an option that have no effect on the compiler behaviour/output.
2752
2815
//
2753
2816
// If the option belongs to the first category, we call `err` macro for a hard error;
2754
2817
// otherwise, we just print a warning with `warn` macro.
2755
- err ! ( optimize) ;
2756
- err ! ( debug_logging) ;
2757
- err ! ( debuginfo_level_rustc) ;
2758
- err ! ( default_linker) ;
2759
- err ! ( rpath) ;
2760
- err ! ( strip) ;
2761
- err ! ( stack_protector) ;
2762
- err ! ( lld_mode) ;
2763
- err ! ( llvm_tools) ;
2764
- err ! ( llvm_bitcode_linker) ;
2765
- err ! ( jemalloc) ;
2766
- err ! ( lto) ;
2767
-
2768
- warn ! ( channel) ;
2769
- warn ! ( description) ;
2770
- warn ! ( incremental) ;
2818
+
2819
+ err ! ( current_rust_config. optimize, optimize) ;
2820
+ err ! ( current_rust_config. debug_logging, debug_logging) ;
2821
+ err ! ( current_rust_config. debuginfo_level_rustc, debuginfo_level_rustc) ;
2822
+ err ! ( current_rust_config. rpath, rpath) ;
2823
+ err ! ( current_rust_config. strip, strip) ;
2824
+ err ! ( current_rust_config. lld_mode, lld_mode) ;
2825
+ err ! ( current_rust_config. llvm_tools, llvm_tools) ;
2826
+ err ! ( current_rust_config. llvm_bitcode_linker, llvm_bitcode_linker) ;
2827
+ err ! ( current_rust_config. jemalloc, jemalloc) ;
2828
+ err ! ( current_rust_config. default_linker, default_linker) ;
2829
+ err ! ( current_rust_config. stack_protector, stack_protector) ;
2830
+ err ! ( current_rust_config. lto, lto) ;
2831
+
2832
+ warn ! ( current_rust_config. channel, channel) ;
2833
+ warn ! ( current_rust_config. description, description) ;
2834
+ warn ! ( current_rust_config. incremental, incremental) ;
2771
2835
2772
2836
Ok ( ( ) )
2773
2837
}
0 commit comments