@@ -453,11 +453,21 @@ impl Config {
453453 skip_std_check_if_no_download_rustc : flags_skip_std_check_if_no_download_rustc,
454454 } = flags;
455455
456+ // First initialize the bare minimum that we need for further operation - source directory
457+ // and execution context.
456458 let mut config = Config :: default_opts ( ) ;
457459 let exec_ctx = ExecutionContext :: new ( flags_verbose, flags_cmd. fail_fast ( ) ) ;
458460
459461 config. exec_ctx = exec_ctx;
460462
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+
461471 // Set flags.
462472 config. paths = std:: mem:: take ( & mut flags_paths) ;
463473
@@ -501,53 +511,6 @@ impl Config {
501511
502512 // Infer the rest of the configuration.
503513
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-
551514 if cfg ! ( test) {
552515 // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
553516 config. out = Path :: new (
@@ -560,47 +523,6 @@ impl Config {
560523
561524 config. stage0_metadata = build_helper:: stage0_parser:: parse_stage0_file ( ) ;
562525
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-
604526 if cfg ! ( test) {
605527 // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the
606528 // same ones used to call the tests (if custom ones are not defined in the toml). If we
@@ -622,7 +544,12 @@ impl Config {
622544 // This must be handled before applying the `profile` since `include`s should always take
623545 // precedence over `profile`s.
624546 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) ;
626553
627554 let included_toml = get_toml ( & include_path) . unwrap_or_else ( |e| {
628555 eprintln ! ( "ERROR: Failed to parse '{}': {e}" , include_path. display( ) ) ;
@@ -2309,3 +2236,104 @@ impl AsRef<ExecutionContext> for Config {
23092236 & self . exec_ctx
23102237 }
23112238}
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