@@ -453,11 +453,21 @@ impl Config {
453
453
skip_std_check_if_no_download_rustc : flags_skip_std_check_if_no_download_rustc,
454
454
} = flags;
455
455
456
+ // First initialize the bare minimum that we need for further operation - source directory
457
+ // and execution context.
456
458
let mut config = Config :: default_opts ( ) ;
457
459
let exec_ctx = ExecutionContext :: new ( flags_verbose, flags_cmd. fail_fast ( ) ) ;
458
460
459
461
config. exec_ctx = exec_ctx;
460
462
463
+ if let Some ( src) = compute_src_directory ( flags_src, & config. exec_ctx ) {
464
+ config. src = src;
465
+ }
466
+
467
+ // Now load the TOML config, as soon as possible
468
+ let ( mut toml, toml_path) = load_toml_config ( & config. src , flags_config, & get_toml) ;
469
+ config. config = toml_path. clone ( ) ;
470
+
461
471
// Set flags.
462
472
config. paths = std:: mem:: take ( & mut flags_paths) ;
463
473
@@ -501,53 +511,6 @@ impl Config {
501
511
502
512
// Infer the rest of the configuration.
503
513
504
- if let Some ( src) = flags_src {
505
- config. src = src
506
- } else {
507
- // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
508
- // running on a completely different machine from where it was compiled.
509
- let mut cmd = helpers:: git ( None ) ;
510
- // NOTE: we cannot support running from outside the repository because the only other path we have available
511
- // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally.
512
- // We still support running outside the repository if we find we aren't in a git directory.
513
-
514
- // NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path,
515
- // and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap
516
- // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
517
- cmd. arg ( "rev-parse" ) . arg ( "--show-cdup" ) ;
518
- // Discard stderr because we expect this to fail when building from a tarball.
519
- let output = cmd. allow_failure ( ) . run_capture_stdout ( & config) ;
520
- if output. is_success ( ) {
521
- let git_root_relative = output. stdout ( ) ;
522
- // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
523
- // and to resolve any relative components.
524
- let git_root = env:: current_dir ( )
525
- . unwrap ( )
526
- . join ( PathBuf :: from ( git_root_relative. trim ( ) ) )
527
- . canonicalize ( )
528
- . unwrap ( ) ;
529
- let s = git_root. to_str ( ) . unwrap ( ) ;
530
-
531
- // Bootstrap is quite bad at handling /? in front of paths
532
- let git_root = match s. strip_prefix ( "\\ \\ ?\\ " ) {
533
- Some ( p) => PathBuf :: from ( p) ,
534
- None => git_root,
535
- } ;
536
- // If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
537
- // for example, the build directory is inside of another unrelated git directory.
538
- // In that case keep the original `CARGO_MANIFEST_DIR` handling.
539
- //
540
- // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
541
- // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
542
- if git_root. join ( "src" ) . join ( "stage0" ) . exists ( ) {
543
- config. src = git_root;
544
- }
545
- } else {
546
- // We're building from a tarball, not git sources.
547
- // We don't support pre-downloaded bootstrap in this case.
548
- }
549
- }
550
-
551
514
if cfg ! ( test) {
552
515
// Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
553
516
config. out = Path :: new (
@@ -560,47 +523,6 @@ impl Config {
560
523
561
524
config. stage0_metadata = build_helper:: stage0_parser:: parse_stage0_file ( ) ;
562
525
563
- // Locate the configuration file using the following priority (first match wins):
564
- // 1. `--config <path>` (explicit flag)
565
- // 2. `RUST_BOOTSTRAP_CONFIG` environment variable
566
- // 3. `./bootstrap.toml` (local file)
567
- // 4. `<root>/bootstrap.toml`
568
- // 5. `./config.toml` (fallback for backward compatibility)
569
- // 6. `<root>/config.toml`
570
- let toml_path = flags_config
571
- . clone ( )
572
- . or_else ( || env:: var_os ( "RUST_BOOTSTRAP_CONFIG" ) . map ( PathBuf :: from) ) ;
573
- let using_default_path = toml_path. is_none ( ) ;
574
- let mut toml_path = toml_path. unwrap_or_else ( || PathBuf :: from ( "bootstrap.toml" ) ) ;
575
-
576
- if using_default_path && !toml_path. exists ( ) {
577
- toml_path = config. src . join ( PathBuf :: from ( "bootstrap.toml" ) ) ;
578
- if !toml_path. exists ( ) {
579
- toml_path = PathBuf :: from ( "config.toml" ) ;
580
- if !toml_path. exists ( ) {
581
- toml_path = config. src . join ( PathBuf :: from ( "config.toml" ) ) ;
582
- }
583
- }
584
- }
585
-
586
- // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
587
- // but not if `bootstrap.toml` hasn't been created.
588
- let mut toml = if !using_default_path || toml_path. exists ( ) {
589
- config. config = Some ( if cfg ! ( not( test) ) {
590
- toml_path = toml_path. canonicalize ( ) . unwrap ( ) ;
591
- toml_path. clone ( )
592
- } else {
593
- toml_path. clone ( )
594
- } ) ;
595
- get_toml ( & toml_path) . unwrap_or_else ( |e| {
596
- eprintln ! ( "ERROR: Failed to parse '{}': {e}" , toml_path. display( ) ) ;
597
- exit ! ( 2 ) ;
598
- } )
599
- } else {
600
- config. config = None ;
601
- TomlConfig :: default ( )
602
- } ;
603
-
604
526
if cfg ! ( test) {
605
527
// When configuring bootstrap for tests, make sure to set the rustc and Cargo to the
606
528
// same ones used to call the tests (if custom ones are not defined in the toml). If we
@@ -622,7 +544,12 @@ impl Config {
622
544
// This must be handled before applying the `profile` since `include`s should always take
623
545
// precedence over `profile`s.
624
546
for include_path in toml. include . clone ( ) . unwrap_or_default ( ) . iter ( ) . rev ( ) {
625
- let include_path = toml_path. parent ( ) . unwrap ( ) . join ( include_path) ;
547
+ let include_path = toml_path
548
+ . as_ref ( )
549
+ . expect ( "include found in default TOML config" )
550
+ . parent ( )
551
+ . unwrap ( )
552
+ . join ( include_path) ;
626
553
627
554
let included_toml = get_toml ( & include_path) . unwrap_or_else ( |e| {
628
555
eprintln ! ( "ERROR: Failed to parse '{}': {e}" , include_path. display( ) ) ;
@@ -2309,3 +2236,104 @@ impl AsRef<ExecutionContext> for Config {
2309
2236
& self . exec_ctx
2310
2237
}
2311
2238
}
2239
+
2240
+ fn compute_src_directory ( src_dir : Option < PathBuf > , exec_ctx : & ExecutionContext ) -> Option < PathBuf > {
2241
+ if let Some ( src) = src_dir {
2242
+ return Some ( src) ;
2243
+ } else {
2244
+ // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
2245
+ // running on a completely different machine from where it was compiled.
2246
+ let mut cmd = helpers:: git ( None ) ;
2247
+ // NOTE: we cannot support running from outside the repository because the only other path we have available
2248
+ // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally.
2249
+ // We still support running outside the repository if we find we aren't in a git directory.
2250
+
2251
+ // NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path,
2252
+ // and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap
2253
+ // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
2254
+ cmd. arg ( "rev-parse" ) . arg ( "--show-cdup" ) ;
2255
+ // Discard stderr because we expect this to fail when building from a tarball.
2256
+ let output = cmd. allow_failure ( ) . run_capture_stdout ( exec_ctx) ;
2257
+ if output. is_success ( ) {
2258
+ let git_root_relative = output. stdout ( ) ;
2259
+ // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
2260
+ // and to resolve any relative components.
2261
+ let git_root = env:: current_dir ( )
2262
+ . unwrap ( )
2263
+ . join ( PathBuf :: from ( git_root_relative. trim ( ) ) )
2264
+ . canonicalize ( )
2265
+ . unwrap ( ) ;
2266
+ let s = git_root. to_str ( ) . unwrap ( ) ;
2267
+
2268
+ // Bootstrap is quite bad at handling /? in front of paths
2269
+ let git_root = match s. strip_prefix ( "\\ \\ ?\\ " ) {
2270
+ Some ( p) => PathBuf :: from ( p) ,
2271
+ None => git_root,
2272
+ } ;
2273
+ // If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
2274
+ // for example, the build directory is inside of another unrelated git directory.
2275
+ // In that case keep the original `CARGO_MANIFEST_DIR` handling.
2276
+ //
2277
+ // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
2278
+ // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
2279
+ if git_root. join ( "src" ) . join ( "stage0" ) . exists ( ) {
2280
+ return Some ( git_root) ;
2281
+ }
2282
+ } else {
2283
+ // We're building from a tarball, not git sources.
2284
+ // We don't support pre-downloaded bootstrap in this case.
2285
+ }
2286
+ } ;
2287
+ None
2288
+ }
2289
+
2290
+ /// Loads bootstrap TOML config and returns the config together with a path from where
2291
+ /// it was loaded.
2292
+ /// `src` is the source root directory, and `config_path` is an optionally provided path to the
2293
+ /// config.
2294
+ fn load_toml_config (
2295
+ src : & Path ,
2296
+ config_path : Option < PathBuf > ,
2297
+ get_toml : & impl Fn ( & Path ) -> Result < TomlConfig , toml:: de:: Error > ,
2298
+ ) -> ( TomlConfig , Option < PathBuf > ) {
2299
+ // Locate the configuration file using the following priority (first match wins):
2300
+ // 1. `--config <path>` (explicit flag)
2301
+ // 2. `RUST_BOOTSTRAP_CONFIG` environment variable
2302
+ // 3. `./bootstrap.toml` (local file)
2303
+ // 4. `<root>/bootstrap.toml`
2304
+ // 5. `./config.toml` (fallback for backward compatibility)
2305
+ // 6. `<root>/config.toml`
2306
+ let toml_path = config_path. or_else ( || env:: var_os ( "RUST_BOOTSTRAP_CONFIG" ) . map ( PathBuf :: from) ) ;
2307
+ let using_default_path = toml_path. is_none ( ) ;
2308
+ let mut toml_path = toml_path. unwrap_or_else ( || PathBuf :: from ( "bootstrap.toml" ) ) ;
2309
+
2310
+ if using_default_path && !toml_path. exists ( ) {
2311
+ toml_path = src. join ( PathBuf :: from ( "bootstrap.toml" ) ) ;
2312
+ if !toml_path. exists ( ) {
2313
+ toml_path = PathBuf :: from ( "config.toml" ) ;
2314
+ if !toml_path. exists ( ) {
2315
+ toml_path = src. join ( PathBuf :: from ( "config.toml" ) ) ;
2316
+ }
2317
+ }
2318
+ }
2319
+
2320
+ // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
2321
+ // but not if `bootstrap.toml` hasn't been created.
2322
+ if !using_default_path || toml_path. exists ( ) {
2323
+ let path = Some ( if cfg ! ( not( test) ) {
2324
+ toml_path = toml_path. canonicalize ( ) . unwrap ( ) ;
2325
+ toml_path. clone ( )
2326
+ } else {
2327
+ toml_path. clone ( )
2328
+ } ) ;
2329
+ (
2330
+ get_toml ( & toml_path) . unwrap_or_else ( |e| {
2331
+ eprintln ! ( "ERROR: Failed to parse '{}': {e}" , toml_path. display( ) ) ;
2332
+ exit ! ( 2 ) ;
2333
+ } ) ,
2334
+ path,
2335
+ )
2336
+ } else {
2337
+ ( TomlConfig :: default ( ) , None )
2338
+ }
2339
+ }
0 commit comments