config.rs 42.6 KB
Newer Older
1 2
//! Serialized configuration of a build.
//!
3 4
//! This module implements parsing `config.toml` configuration files to tweak
//! how the build runs.
5

M
Mark Rousskov 已提交
6
use std::cmp;
7
use std::collections::{HashMap, HashSet};
A
Alex Crichton 已提交
8
use std::env;
A
Adam Perry 已提交
9
use std::ffi::OsString;
10
use std::fmt;
11
use std::fs;
12
use std::path::{Path, PathBuf};
13
use std::str::FromStr;
A
Alex Crichton 已提交
14

M
Mark Rousskov 已提交
15
use crate::cache::{Interned, INTERNER};
16
use crate::channel::GitInfo;
L
ljedrz 已提交
17
pub use crate::flags::Subcommand;
J
Joshua Nelson 已提交
18
use crate::flags::{Color, Flags};
19
use crate::util::exe;
M
Mark Rousskov 已提交
20
use build_helper::t;
21
use merge::Merge;
M
Mark Rousskov 已提交
22
use serde::Deserialize;
A
Alex Crichton 已提交
23

24 25 26 27 28 29 30 31 32 33
macro_rules! check_ci_llvm {
    ($name:expr) => {
        assert!(
            $name.is_none(),
            "setting {} is incompatible with download-ci-llvm.",
            stringify!($name)
        );
    };
}

A
Alex Crichton 已提交
34 35 36 37 38 39 40 41
/// Global configuration for the entire build and/or bootstrap.
///
/// This structure is derived from a combination of both `config.toml` and
/// `config.mk`. As of the time of this writing it's unlikely that `config.toml`
/// is used all that much, so this is primarily filled out by `config.mk` which
/// is generated from `./configure`.
///
/// Note that this structure is not decoded directly into, but rather it is
42 43
/// filled out from the decoded forms of the structs below. For documentation
/// each field, see the corresponding fields in
44
/// `config.toml.example`.
A
Alex Crichton 已提交
45 46
#[derive(Default)]
pub struct Config {
J
Joshua Nelson 已提交
47
    pub changelog_seen: Option<usize>,
A
Alex Crichton 已提交
48
    pub ccache: Option<String>,
49 50
    /// Call Build::ninja() instead of this.
    pub ninja_in_file: bool,
51
    pub verbose: usize,
52
    pub submodules: Option<bool>,
53
    pub fast_submodules: bool,
A
Alex Crichton 已提交
54
    pub compiler_docs: bool,
55
    pub docs_minification: bool,
A
Alex Crichton 已提交
56
    pub docs: bool,
57
    pub locked_deps: bool,
58
    pub vendor: bool,
59
    pub target_config: HashMap<TargetSelection, Target>,
60
    pub full_bootstrap: bool,
61
    pub extended: bool,
62
    pub tools: Option<HashSet<String>>,
63
    pub sanitizers: bool,
64
    pub profiler: bool,
65
    pub ignore_git: bool,
66
    pub exclude: Vec<PathBuf>,
67
    pub include_default_paths: bool,
P
penpalperson 已提交
68
    pub rustc_error_format: Option<String>,
69
    pub json_output: bool,
70
    pub test_compare_mode: bool,
71
    pub llvm_libunwind: LlvmLibunwind,
J
Joshua Nelson 已提交
72
    pub color: Color,
A
Alex Crichton 已提交
73

M
Mark Simulacrum 已提交
74
    pub on_fail: Option<String>,
75
    pub stage: u32,
76
    pub keep_stage: Vec<u32>,
D
Dylan MacKenzie 已提交
77
    pub keep_stage_std: Vec<u32>,
M
Mark Simulacrum 已提交
78
    pub src: PathBuf,
J
Joshua Nelson 已提交
79 80
    // defaults to `config.toml`
    pub config: PathBuf,
M
Mark Simulacrum 已提交
81 82 83
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
84
    pub dry_run: bool,
85
    pub download_rustc: bool,
M
Mark Simulacrum 已提交
86

87
    pub deny_warnings: bool,
J
John Kåre Alsaker 已提交
88
    pub backtrace_on_ice: bool,
89

A
Alex Crichton 已提交
90
    // llvm codegen options
91
    pub llvm_skip_rebuild: bool,
A
Alex Crichton 已提交
92
    pub llvm_assertions: bool,
93
    pub llvm_tests: bool,
94
    pub llvm_plugins: bool,
A
Alex Crichton 已提交
95
    pub llvm_optimize: bool,
96
    pub llvm_thin_lto: bool,
97
    pub llvm_release_debuginfo: bool,
A
Alex Crichton 已提交
98 99
    pub llvm_version_check: bool,
    pub llvm_static_stdcpp: bool,
100
    pub llvm_link_shared: bool,
101
    pub llvm_clang_cl: Option<String>,
102
    pub llvm_targets: Option<String>,
103
    pub llvm_experimental_targets: Option<String>,
104
    pub llvm_link_jobs: Option<u32>,
105
    pub llvm_version_suffix: Option<String>,
106
    pub llvm_use_linker: Option<String>,
107 108
    pub llvm_allow_old_toolchain: bool,
    pub llvm_polly: bool,
109
    pub llvm_clang: bool,
110
    pub llvm_from_ci: bool,
A
Alex Crichton 已提交
111

112
    pub use_lld: bool,
113
    pub lld_enabled: bool,
114
    pub llvm_tools_enabled: bool,
115

116 117 118
    pub llvm_cflags: Option<String>,
    pub llvm_cxxflags: Option<String>,
    pub llvm_ldflags: Option<String>,
119 120
    pub llvm_use_libcxx: bool,

A
Alex Crichton 已提交
121 122
    // rust codegen options
    pub rust_optimize: bool,
123
    pub rust_codegen_units: Option<u32>,
124
    pub rust_codegen_units_std: Option<u32>,
A
Alex Crichton 已提交
125
    pub rust_debug_assertions: bool,
126
    pub rust_debug_assertions_std: bool,
127 128
    pub rust_overflow_checks: bool,
    pub rust_overflow_checks_std: bool,
G
Gus Wynn 已提交
129
    pub rust_debug_logging: bool,
130 131 132 133
    pub rust_debuginfo_level_rustc: u32,
    pub rust_debuginfo_level_std: u32,
    pub rust_debuginfo_level_tools: u32,
    pub rust_debuginfo_level_tests: u32,
134
    pub rust_run_dsymutil: bool,
A
Alex Crichton 已提交
135
    pub rust_rpath: bool,
136
    pub rustc_parallel: bool,
A
Alex Crichton 已提交
137
    pub rustc_default_linker: Option<String>,
138
    pub rust_optimize_tests: bool,
139
    pub rust_dist_src: bool,
140
    pub rust_codegen_backends: Vec<Interned<String>>,
141
    pub rust_verify_llvm_ir: bool,
142
    pub rust_thin_lto_import_instr_limit: Option<u32>,
143
    pub rust_remap_debuginfo: bool,
144
    pub rust_new_symbol_mangling: bool,
145 146
    pub rust_profile_use: Option<String>,
    pub rust_profile_generate: Option<String>,
147 148
    pub llvm_profile_use: Option<String>,
    pub llvm_profile_generate: bool,
A
Alex Crichton 已提交
149

150 151 152
    pub build: TargetSelection,
    pub hosts: Vec<TargetSelection>,
    pub targets: Vec<TargetSelection>,
153
    pub local_rebuild: bool,
154
    pub jemalloc: bool,
155
    pub control_flow_guard: bool,
A
Alex Crichton 已提交
156

157 158 159
    // dist misc
    pub dist_sign_folder: Option<PathBuf>,
    pub dist_upload_addr: Option<String>,
160
    pub dist_compression_formats: Option<Vec<String>>,
161

A
Alex Crichton 已提交
162
    // libstd features
163
    pub backtrace: bool, // support for RUST_BACKTRACE
A
Alex Crichton 已提交
164 165

    // misc
166
    pub low_priority: bool,
A
Alex Crichton 已提交
167
    pub channel: String,
168
    pub description: Option<String>,
O
Oliver Schneider 已提交
169
    pub verbose_tests: bool,
170
    pub save_toolstates: Option<PathBuf>,
171
    pub print_step_timings: bool,
172
    pub print_step_rusage: bool,
173
    pub missing_tools: bool,
174

J
Jorge Aparicio 已提交
175
    // Fallback musl-root for all targets
A
Alex Crichton 已提交
176
    pub musl_root: Option<PathBuf>,
177
    pub prefix: Option<PathBuf>,
178
    pub sysconfdir: Option<PathBuf>,
179
    pub datadir: Option<PathBuf>,
180
    pub docdir: Option<PathBuf>,
181
    pub bindir: PathBuf,
182 183
    pub libdir: Option<PathBuf>,
    pub mandir: Option<PathBuf>,
184
    pub codegen_tests: bool,
185
    pub nodejs: Option<PathBuf>,
G
Guillaume Gomez 已提交
186
    pub npm: Option<PathBuf>,
187
    pub gdb: Option<PathBuf>,
188
    pub python: Option<PathBuf>,
189
    pub cargo_native_static: bool,
190
    pub configure_args: Vec<String>,
191 192 193 194

    // These are either the stage0 downloaded binaries or the locally installed ones.
    pub initial_cargo: PathBuf,
    pub initial_rustc: PathBuf,
A
Adam Perry 已提交
195
    pub initial_rustfmt: Option<PathBuf>,
196
    pub out: PathBuf,
A
Alex Crichton 已提交
197 198
}

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LlvmLibunwind {
    No,
    InTree,
    System,
}

impl Default for LlvmLibunwind {
    fn default() -> Self {
        Self::No
    }
}

impl FromStr for LlvmLibunwind {
    type Err = String;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "no" => Ok(Self::No),
            "in-tree" => Ok(Self::InTree),
            "system" => Ok(Self::System),
            invalid => Err(format!("Invalid value '{}' for rust.llvm-libunwind config.", invalid)),
        }
    }
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TargetSelection {
    pub triple: Interned<String>,
    file: Option<Interned<String>>,
}

impl TargetSelection {
    pub fn from_user(selection: &str) -> Self {
        let path = Path::new(selection);

        let (triple, file) = if path.exists() {
            let triple = path
                .file_stem()
                .expect("Target specification file has no file stem")
                .to_str()
                .expect("Target specification file stem is not UTF-8");

            (triple, Some(selection))
        } else {
            (selection, None)
        };

        let triple = INTERNER.intern_str(triple);
        let file = file.map(|f| INTERNER.intern_str(f));

        Self { triple, file }
    }

    pub fn rustc_target_arg(&self) -> &str {
        self.file.as_ref().unwrap_or(&self.triple)
    }

    pub fn contains(&self, needle: &str) -> bool {
        self.triple.contains(needle)
    }

    pub fn starts_with(&self, needle: &str) -> bool {
        self.triple.starts_with(needle)
    }

    pub fn ends_with(&self, needle: &str) -> bool {
        self.triple.ends_with(needle)
    }
}

impl fmt::Display for TargetSelection {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.triple)?;
        if let Some(file) = self.file {
            write!(f, "({})", file)?;
        }
        Ok(())
    }
}

impl PartialEq<&str> for TargetSelection {
    fn eq(&self, other: &&str) -> bool {
        self.triple == *other
    }
}

A
Alex Crichton 已提交
286 287 288
/// Per-target configuration stored in the global configuration structure.
#[derive(Default)]
pub struct Target {
289
    /// Some(path to llvm-config) if using an external LLVM.
A
Alex Crichton 已提交
290
    pub llvm_config: Option<PathBuf>,
291 292
    /// Some(path to FileCheck) if one was specified.
    pub llvm_filecheck: Option<PathBuf>,
A
Alex Crichton 已提交
293 294
    pub cc: Option<PathBuf>,
    pub cxx: Option<PathBuf>,
295
    pub ar: Option<PathBuf>,
296
    pub ranlib: Option<PathBuf>,
297
    pub linker: Option<PathBuf>,
A
Alex Crichton 已提交
298
    pub ndk: Option<PathBuf>,
299 300
    pub sanitizers: Option<bool>,
    pub profiler: Option<bool>,
301
    pub crt_static: Option<bool>,
J
Jorge Aparicio 已提交
302
    pub musl_root: Option<PathBuf>,
303
    pub musl_libdir: Option<PathBuf>,
304
    pub wasi_root: Option<PathBuf>,
305
    pub qemu_rootfs: Option<PathBuf>,
306
    pub no_std: bool,
A
Alex Crichton 已提交
307 308
}

309 310 311
impl Target {
    pub fn from_triple(triple: &str) -> Self {
        let mut target: Self = Default::default();
312
        if triple.contains("-none") || triple.contains("nvptx") {
313 314 315 316 317
            target.no_std = true;
        }
        target
    }
}
A
Alex Crichton 已提交
318 319 320 321 322
/// Structure of the `config.toml` file that configuration is read from.
///
/// This structure uses `Decodable` to automatically decode a TOML configuration
/// file into this format, and then this is traversed and written into the above
/// `Config` structure.
M
Mark Simulacrum 已提交
323
#[derive(Deserialize, Default)]
324
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
A
Alex Crichton 已提交
325
struct TomlConfig {
J
Joshua Nelson 已提交
326
    changelog_seen: Option<usize>,
A
Alex Crichton 已提交
327
    build: Option<Build>,
J
Jeremy Soller 已提交
328
    install: Option<Install>,
A
Alex Crichton 已提交
329 330 331
    llvm: Option<Llvm>,
    rust: Option<Rust>,
    target: Option<HashMap<String, TomlTarget>>,
332
    dist: Option<Dist>,
333 334 335 336
    profile: Option<String>,
}

impl Merge for TomlConfig {
J
Joshua Nelson 已提交
337 338 339 340
    fn merge(
        &mut self,
        TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self,
    ) {
341 342 343 344 345 346 347 348
        fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>) {
            if let Some(new) = y {
                if let Some(original) = x {
                    original.merge(new);
                } else {
                    *x = Some(new);
                }
            }
349
        }
350 351 352 353 354 355 356
        do_merge(&mut self.build, build);
        do_merge(&mut self.install, install);
        do_merge(&mut self.llvm, llvm);
        do_merge(&mut self.rust, rust);
        do_merge(&mut self.dist, dist);
        assert!(target.is_none(), "merging target-specific config is not currently supported");
    }
A
Alex Crichton 已提交
357 358 359
}

/// TOML representation of various global build decisions.
360
#[derive(Deserialize, Default, Clone, Merge)]
361
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
A
Alex Crichton 已提交
362 363
struct Build {
    build: Option<String>,
364 365
    host: Option<Vec<String>>,
    target: Option<Vec<String>>,
366 367
    // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
    build_dir: Option<String>,
A
Alex Crichton 已提交
368 369
    cargo: Option<String>,
    rustc: Option<String>,
370
    rustfmt: Option<PathBuf>,
A
Alex Crichton 已提交
371
    docs: Option<bool>,
372
    compiler_docs: Option<bool>,
373
    docs_minification: Option<bool>,
374
    submodules: Option<bool>,
375
    fast_submodules: Option<bool>,
376
    gdb: Option<String>,
377
    nodejs: Option<String>,
G
Guillaume Gomez 已提交
378
    npm: Option<String>,
379
    python: Option<String>,
380 381
    locked_deps: Option<bool>,
    vendor: Option<bool>,
382
    full_bootstrap: Option<bool>,
383
    extended: Option<bool>,
384
    tools: Option<HashSet<String>>,
385
    verbose: Option<usize>,
386
    sanitizers: Option<bool>,
387
    profiler: Option<bool>,
388
    cargo_native_static: Option<bool>,
389
    low_priority: Option<bool>,
390 391
    configure_args: Option<Vec<String>>,
    local_rebuild: Option<bool>,
392
    print_step_timings: Option<bool>,
393
    print_step_rusage: Option<bool>,
394
    check_stage: Option<u32>,
395 396 397 398 399 400
    doc_stage: Option<u32>,
    build_stage: Option<u32>,
    test_stage: Option<u32>,
    install_stage: Option<u32>,
    dist_stage: Option<u32>,
    bench_stage: Option<u32>,
401
    patch_binaries_for_nix: Option<bool>,
A
Alex Crichton 已提交
402 403
}

J
Jeremy Soller 已提交
404
/// TOML representation of various global install decisions.
405
#[derive(Deserialize, Default, Clone, Merge)]
406
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
J
Jeremy Soller 已提交
407 408
struct Install {
    prefix: Option<String>,
409
    sysconfdir: Option<String>,
410
    docdir: Option<String>,
411
    bindir: Option<String>,
412
    libdir: Option<String>,
413
    mandir: Option<String>,
414
    datadir: Option<String>,
J
Jeremy Soller 已提交
415 416
}

A
Alex Crichton 已提交
417
/// TOML representation of how the LLVM build is configured.
418
#[derive(Deserialize, Default, Merge)]
419
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
A
Alex Crichton 已提交
420
struct Llvm {
421
    skip_rebuild: Option<bool>,
A
Alex Crichton 已提交
422
    optimize: Option<bool>,
423
    thin_lto: Option<bool>,
424
    release_debuginfo: Option<bool>,
425
    assertions: Option<bool>,
426
    tests: Option<bool>,
427
    plugins: Option<bool>,
428
    ccache: Option<StringOrBool>,
A
Alex Crichton 已提交
429 430
    version_check: Option<bool>,
    static_libstdcpp: Option<bool>,
431
    ninja: Option<bool>,
432
    targets: Option<String>,
433
    experimental_targets: Option<String>,
434
    link_jobs: Option<u32>,
435
    link_shared: Option<bool>,
436
    version_suffix: Option<String>,
437
    clang_cl: Option<String>,
438 439 440
    cflags: Option<String>,
    cxxflags: Option<String>,
    ldflags: Option<String>,
441
    use_libcxx: Option<bool>,
442
    use_linker: Option<String>,
443
    allow_old_toolchain: Option<bool>,
444
    polly: Option<bool>,
445
    clang: Option<bool>,
446
    download_ci_llvm: Option<StringOrBool>,
A
Alex Crichton 已提交
447 448
}

449
#[derive(Deserialize, Default, Clone, Merge)]
450
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
451 452 453 454
struct Dist {
    sign_folder: Option<String>,
    gpg_password_file: Option<String>,
    upload_addr: Option<String>,
455
    src_tarball: Option<bool>,
456
    missing_tools: Option<bool>,
457
    compression_formats: Option<Vec<String>>,
458 459
}

M
Mark Simulacrum 已提交
460 461
#[derive(Deserialize)]
#[serde(untagged)]
A
Alex Crichton 已提交
462 463 464 465 466 467 468 469 470 471 472
enum StringOrBool {
    String(String),
    Bool(bool),
}

impl Default for StringOrBool {
    fn default() -> StringOrBool {
        StringOrBool::Bool(false)
    }
}

A
Alex Crichton 已提交
473
/// TOML representation of how the Rust build is configured.
474
#[derive(Deserialize, Default, Merge)]
475
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
A
Alex Crichton 已提交
476 477
struct Rust {
    optimize: Option<bool>,
478
    debug: Option<bool>,
A
Alex Crichton 已提交
479
    codegen_units: Option<u32>,
480
    codegen_units_std: Option<u32>,
A
Alex Crichton 已提交
481
    debug_assertions: Option<bool>,
482
    debug_assertions_std: Option<bool>,
483 484
    overflow_checks: Option<bool>,
    overflow_checks_std: Option<bool>,
G
Gus Wynn 已提交
485
    debug_logging: Option<bool>,
486 487 488 489 490
    debuginfo_level: Option<u32>,
    debuginfo_level_rustc: Option<u32>,
    debuginfo_level_std: Option<u32>,
    debuginfo_level_tools: Option<u32>,
    debuginfo_level_tests: Option<u32>,
491
    run_dsymutil: Option<bool>,
492
    backtrace: Option<bool>,
493 494
    incremental: Option<bool>,
    parallel_compiler: Option<bool>,
A
Alex Crichton 已提交
495 496
    default_linker: Option<String>,
    channel: Option<String>,
497
    description: Option<String>,
A
Alex Crichton 已提交
498 499
    musl_root: Option<String>,
    rpath: Option<bool>,
500
    verbose_tests: Option<bool>,
501
    optimize_tests: Option<bool>,
502
    codegen_tests: Option<bool>,
503
    ignore_git: Option<bool>,
504
    dist_src: Option<bool>,
505
    save_toolstates: Option<String>,
506
    codegen_backends: Option<Vec<String>>,
507
    lld: Option<bool>,
508
    use_lld: Option<bool>,
509
    llvm_tools: Option<bool>,
510
    deny_warnings: Option<bool>,
J
John Kåre Alsaker 已提交
511
    backtrace_on_ice: Option<bool>,
512
    verify_llvm_ir: Option<bool>,
513
    thin_lto_import_instr_limit: Option<u32>,
514
    remap_debuginfo: Option<bool>,
515
    jemalloc: Option<bool>,
516
    test_compare_mode: Option<bool>,
517
    llvm_libunwind: Option<String>,
518
    control_flow_guard: Option<bool>,
519
    new_symbol_mangling: Option<bool>,
520 521
    profile_generate: Option<String>,
    profile_use: Option<String>,
522 523
    // ignored; this is set from an env var set by bootstrap.py
    download_rustc: Option<StringOrBool>,
A
Alex Crichton 已提交
524 525 526
}

/// TOML representation of how each build target is configured.
527
#[derive(Deserialize, Default, Merge)]
528
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
A
Alex Crichton 已提交
529 530 531
struct TomlTarget {
    cc: Option<String>,
    cxx: Option<String>,
532
    ar: Option<String>,
533
    ranlib: Option<String>,
534
    linker: Option<String>,
535 536
    llvm_config: Option<String>,
    llvm_filecheck: Option<String>,
A
Alex Crichton 已提交
537
    android_ndk: Option<String>,
538 539
    sanitizers: Option<bool>,
    profiler: Option<bool>,
540
    crt_static: Option<bool>,
541
    musl_root: Option<String>,
542
    musl_libdir: Option<String>,
543
    wasi_root: Option<String>,
544
    qemu_rootfs: Option<String>,
545
    no_std: Option<bool>,
A
Alex Crichton 已提交
546 547 548
}

impl Config {
549 550
    fn path_from_python(var_key: &str) -> PathBuf {
        match env::var_os(var_key) {
A
Adam Perry 已提交
551
            Some(var_val) => Self::normalize_python_path(var_val),
552 553 554 555
            _ => panic!("expected '{}' to be set", var_key),
        }
    }

A
Adam Perry 已提交
556 557 558 559 560
    /// Normalizes paths from Python slightly. We don't trust paths from Python (#49785).
    fn normalize_python_path(path: OsString) -> PathBuf {
        Path::new(&path).components().collect()
    }

561
    pub fn default_opts() -> Config {
A
Alex Crichton 已提交
562 563
        let mut config = Config::default();
        config.llvm_optimize = true;
564
        config.ninja_in_file = true;
565
        config.llvm_version_check = true;
566
        config.backtrace = true;
A
Alex Crichton 已提交
567
        config.rust_optimize = true;
568
        config.rust_optimize_tests = true;
569
        config.submodules = None;
570
        config.fast_submodules = true;
A
Alex Crichton 已提交
571
        config.docs = true;
572
        config.docs_minification = true;
A
Alex Crichton 已提交
573 574
        config.rust_rpath = true;
        config.channel = "dev".to_string();
575
        config.codegen_tests = true;
576
        config.rust_dist_src = true;
577
        config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
578
        config.deny_warnings = true;
579
        config.bindir = "bin".into();
A
Alex Crichton 已提交
580

N
nooberfsh 已提交
581
        // set by build.rs
582
        config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
583 584 585
        let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        // Undo `src/bootstrap`
        config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
586
        config.out = Config::path_from_python("BUILD_DIR");
587

588 589
        config.initial_cargo = PathBuf::from(env!("CARGO"));
        config.initial_rustc = PathBuf::from(env!("RUSTC"));
590 591 592 593 594 595

        config
    }

    pub fn parse(args: &[String]) -> Config {
        let flags = Flags::parse(&args);
596

597 598
        let mut config = Config::default_opts();
        config.exclude = flags.exclude;
599
        config.include_default_paths = flags.include_default_paths;
P
penpalperson 已提交
600
        config.rustc_error_format = flags.rustc_error_format;
601
        config.json_output = flags.json_output;
M
Mark Simulacrum 已提交
602
        config.on_fail = flags.on_fail;
603
        config.jobs = flags.jobs.map(threads_from_config);
M
Mark Simulacrum 已提交
604 605
        config.cmd = flags.cmd;
        config.incremental = flags.incremental;
606
        config.dry_run = flags.dry_run;
M
Mark Simulacrum 已提交
607
        config.keep_stage = flags.keep_stage;
D
Dylan MacKenzie 已提交
608
        config.keep_stage_std = flags.keep_stage_std;
J
Joshua Nelson 已提交
609
        config.color = flags.color;
610
        if let Some(value) = flags.deny_warnings {
611 612
            config.deny_warnings = value;
        }
613 614
        config.llvm_profile_use = flags.llvm_profile_use;
        config.llvm_profile_generate = flags.llvm_profile_generate;
M
Mark Simulacrum 已提交
615

616 617 618 619 620 621
        if config.dry_run {
            let dir = config.out.join("tmp-dry-run");
            t!(fs::create_dir_all(&dir));
            config.out = dir;
        }

622
        #[cfg(test)]
623
        let get_toml = |_| TomlConfig::default();
624
        #[cfg(not(test))]
625
        let get_toml = |file: &Path| {
626 627
            use std::process;

628
            let contents = t!(fs::read_to_string(file), "`include` config not found");
629 630 631 632 633
            match toml::from_str(&contents) {
                Ok(table) => table,
                Err(err) => {
                    println!("failed to parse TOML configuration '{}': {}", file.display(), err);
                    process::exit(2);
A
Alex Crichton 已提交
634
                }
635 636 637
            }
        };

638
        let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
639 640 641 642 643
        if let Some(include) = &toml.profile {
            let mut include_path = config.src.clone();
            include_path.push("src");
            include_path.push("bootstrap");
            include_path.push("defaults");
644
            include_path.push(format!("config.{}.toml", include));
645
            let included_toml = get_toml(&include_path);
646 647
            toml.merge(included_toml);
        }
A
Alex Crichton 已提交
648

J
Joshua Nelson 已提交
649
        config.changelog_seen = toml.changelog_seen;
650 651 652
        if let Some(cfg) = flags.config {
            config.config = cfg;
        }
J
Joshua Nelson 已提交
653

654
        let build = toml.build.unwrap_or_default();
655

656
        config.hosts = if let Some(arg_host) = flags.host {
657 658 659 660 661 662
            arg_host
        } else if let Some(file_host) = build.host {
            file_host.iter().map(|h| TargetSelection::from_user(h)).collect()
        } else {
            vec![config.build]
        };
663
        config.targets = if let Some(arg_target) = flags.target {
664 665 666 667 668 669 670 671
            arg_target
        } else if let Some(file_target) = build.target {
            file_target.iter().map(|h| TargetSelection::from_user(h)).collect()
        } else {
            // If target is *not* configured, then default to the host
            // toolchains.
            config.hosts.clone()
        };
672

673
        config.nodejs = build.nodejs.map(PathBuf::from);
G
Guillaume Gomez 已提交
674
        config.npm = build.npm.map(PathBuf::from);
675
        config.gdb = build.gdb.map(PathBuf::from);
676
        config.python = build.python.map(PathBuf::from);
677
        config.submodules = build.submodules;
678
        set(&mut config.low_priority, build.low_priority);
A
Alex Crichton 已提交
679
        set(&mut config.compiler_docs, build.compiler_docs);
680
        set(&mut config.docs_minification, build.docs_minification);
A
Alex Crichton 已提交
681
        set(&mut config.docs, build.docs);
682
        set(&mut config.fast_submodules, build.fast_submodules);
683
        set(&mut config.locked_deps, build.locked_deps);
684
        set(&mut config.vendor, build.vendor);
685
        set(&mut config.full_bootstrap, build.full_bootstrap);
686
        set(&mut config.extended, build.extended);
687
        config.tools = build.tools;
688 689 690
        if build.rustfmt.is_some() {
            config.initial_rustfmt = build.rustfmt;
        }
691
        set(&mut config.verbose, build.verbose);
692
        set(&mut config.sanitizers, build.sanitizers);
693
        set(&mut config.profiler, build.profiler);
694
        set(&mut config.cargo_native_static, build.cargo_native_static);
695 696
        set(&mut config.configure_args, build.configure_args);
        set(&mut config.local_rebuild, build.local_rebuild);
697
        set(&mut config.print_step_timings, build.print_step_timings);
698
        set(&mut config.print_step_rusage, build.print_step_rusage);
699

M
Mark Simulacrum 已提交
700
        config.verbose = cmp::max(config.verbose, flags.verbose);
A
Alex Crichton 已提交
701

702 703 704 705 706 707 708 709
        if let Some(install) = toml.install {
            config.prefix = install.prefix.map(PathBuf::from);
            config.sysconfdir = install.sysconfdir.map(PathBuf::from);
            config.datadir = install.datadir.map(PathBuf::from);
            config.docdir = install.docdir.map(PathBuf::from);
            set(&mut config.bindir, install.bindir.map(PathBuf::from));
            config.libdir = install.libdir.map(PathBuf::from);
            config.mandir = install.mandir.map(PathBuf::from);
J
Jeremy Soller 已提交
710 711
        }

712 713 714 715 716
        // We want the llvm-skip-rebuild flag to take precedence over the
        // skip-rebuild config.toml option so we store it separately
        // so that we can infer the right value
        let mut llvm_skip_rebuild = flags.llvm_skip_rebuild;

717 718 719
        // Store off these values as options because if they're not provided
        // we'll infer default values for them later
        let mut llvm_assertions = None;
720
        let mut llvm_tests = None;
721
        let mut llvm_plugins = None;
722 723
        let mut debug = None;
        let mut debug_assertions = None;
724
        let mut debug_assertions_std = None;
725 726
        let mut overflow_checks = None;
        let mut overflow_checks_std = None;
G
Gus Wynn 已提交
727
        let mut debug_logging = None;
728 729 730 731 732
        let mut debuginfo_level = None;
        let mut debuginfo_level_rustc = None;
        let mut debuginfo_level_std = None;
        let mut debuginfo_level_tools = None;
        let mut debuginfo_level_tests = None;
733
        let mut optimize = None;
734
        let mut ignore_git = None;
735

736
        if let Some(llvm) = toml.llvm {
A
Alex Crichton 已提交
737
            match llvm.ccache {
M
Mark Rousskov 已提交
738
                Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()),
A
Alex Crichton 已提交
739 740 741 742 743
                Some(StringOrBool::Bool(true)) => {
                    config.ccache = Some("ccache".to_string());
                }
                Some(StringOrBool::Bool(false)) | None => {}
            }
744
            set(&mut config.ninja_in_file, llvm.ninja);
745
            llvm_assertions = llvm.assertions;
746
            llvm_tests = llvm.tests;
747
            llvm_plugins = llvm.plugins;
748
            llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild);
A
Alex Crichton 已提交
749
            set(&mut config.llvm_optimize, llvm.optimize);
750
            set(&mut config.llvm_thin_lto, llvm.thin_lto);
751
            set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
A
Alex Crichton 已提交
752 753
            set(&mut config.llvm_version_check, llvm.version_check);
            set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
754
            set(&mut config.llvm_link_shared, llvm.link_shared);
755
            config.llvm_targets = llvm.targets.clone();
756
            config.llvm_experimental_targets = llvm.experimental_targets.clone();
757
            config.llvm_link_jobs = llvm.link_jobs;
758
            config.llvm_version_suffix = llvm.version_suffix.clone();
759
            config.llvm_clang_cl = llvm.clang_cl.clone();
760 761 762 763

            config.llvm_cflags = llvm.cflags.clone();
            config.llvm_cxxflags = llvm.cxxflags.clone();
            config.llvm_ldflags = llvm.ldflags.clone();
764
            set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
765
            config.llvm_use_linker = llvm.use_linker.clone();
766 767
            config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.unwrap_or(false);
            config.llvm_polly = llvm.polly.unwrap_or(false);
768
            config.llvm_clang = llvm.clang.unwrap_or(false);
769 770 771
            config.llvm_from_ci = match llvm.download_ci_llvm {
                Some(StringOrBool::String(s)) => {
                    assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
772 773
                    // This is currently all tier 1 targets and tier 2 targets with host tools
                    // (since others may not have CI artifacts)
774 775 776
                    // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
                    // FIXME: this is duplicated in bootstrap.py
                    let supported_platforms = [
777
                        // tier 1
778 779 780 781 782 783 784 785
                        "aarch64-unknown-linux-gnu",
                        "i686-pc-windows-gnu",
                        "i686-pc-windows-msvc",
                        "i686-unknown-linux-gnu",
                        "x86_64-unknown-linux-gnu",
                        "x86_64-apple-darwin",
                        "x86_64-pc-windows-gnu",
                        "x86_64-pc-windows-msvc",
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
                        // tier 2 with host tools
                        "aarch64-apple-darwin",
                        "aarch64-pc-windows-msvc",
                        "aarch64-unknown-linux-musl",
                        "arm-unknown-linux-gnueabi",
                        "arm-unknown-linux-gnueabihf",
                        "armv7-unknown-linux-gnueabihf",
                        "mips-unknown-linux-gnu",
                        "mips64-unknown-linux-gnuabi64",
                        "mips64el-unknown-linux-gnuabi64",
                        "mipsel-unknown-linux-gnu",
                        "powerpc-unknown-linux-gnu",
                        "powerpc64-unknown-linux-gnu",
                        "powerpc64le-unknown-linux-gnu",
                        "riscv64gc-unknown-linux-gnu",
                        "s390x-unknown-linux-gnu",
                        "x86_64-unknown-freebsd",
                        "x86_64-unknown-illumos",
                        "x86_64-unknown-linux-musl",
                        "x86_64-unknown-netbsd",
806 807
                    ];
                    supported_platforms.contains(&&*config.build.triple)
808 809 810 811
                }
                Some(StringOrBool::Bool(b)) => b,
                None => false,
            };
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835

            if config.llvm_from_ci {
                // None of the LLVM options, except assertions, are supported
                // when using downloaded LLVM. We could just ignore these but
                // that's potentially confusing, so force them to not be
                // explicitly set. The defaults and CI defaults don't
                // necessarily match but forcing people to match (somewhat
                // arbitrary) CI configuration locally seems bad/hard.
                check_ci_llvm!(llvm.optimize);
                check_ci_llvm!(llvm.thin_lto);
                check_ci_llvm!(llvm.release_debuginfo);
                check_ci_llvm!(llvm.link_shared);
                check_ci_llvm!(llvm.static_libstdcpp);
                check_ci_llvm!(llvm.targets);
                check_ci_llvm!(llvm.experimental_targets);
                check_ci_llvm!(llvm.link_jobs);
                check_ci_llvm!(llvm.clang_cl);
                check_ci_llvm!(llvm.version_suffix);
                check_ci_llvm!(llvm.cflags);
                check_ci_llvm!(llvm.cxxflags);
                check_ci_llvm!(llvm.ldflags);
                check_ci_llvm!(llvm.use_libcxx);
                check_ci_llvm!(llvm.use_linker);
                check_ci_llvm!(llvm.allow_old_toolchain);
836
                check_ci_llvm!(llvm.polly);
837 838
                check_ci_llvm!(llvm.clang);
                check_ci_llvm!(llvm.plugins);
839

840 841
                // CI-built LLVM can be either dynamic or static.
                let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm");
842 843 844 845 846 847 848 849 850 851
                config.llvm_link_shared = if config.dry_run {
                    // just assume dynamic for now
                    true
                } else {
                    let link_type = t!(
                        std::fs::read_to_string(ci_llvm.join("link-type.txt")),
                        format!("CI llvm missing: {}", ci_llvm.display())
                    );
                    link_type == "dynamic"
                };
852 853
            }

854 855 856 857
            if config.llvm_thin_lto && llvm.link_shared.is_none() {
                // If we're building with ThinLTO on, by default we want to link
                // to LLVM shared, to avoid re-doing ThinLTO (which happens in
                // the link step) with each stage.
858
                config.llvm_link_shared = true;
859
            }
A
Alex Crichton 已提交
860
        }
J
Jeremy Soller 已提交
861

862
        if let Some(rust) = toml.rust {
863 864
            debug = rust.debug;
            debug_assertions = rust.debug_assertions;
865
            debug_assertions_std = rust.debug_assertions_std;
866 867
            overflow_checks = rust.overflow_checks;
            overflow_checks_std = rust.overflow_checks_std;
G
Gus Wynn 已提交
868
            debug_logging = rust.debug_logging;
869 870 871 872 873
            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;
874
            config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
875
            optimize = rust.optimize;
876
            ignore_git = rust.ignore_git;
877
            set(&mut config.rust_new_symbol_mangling, rust.new_symbol_mangling);
878
            set(&mut config.rust_optimize_tests, rust.optimize_tests);
879
            set(&mut config.codegen_tests, rust.codegen_tests);
A
Alex Crichton 已提交
880
            set(&mut config.rust_rpath, rust.rpath);
881
            set(&mut config.jemalloc, rust.jemalloc);
882
            set(&mut config.test_compare_mode, rust.test_compare_mode);
883 884
            config.llvm_libunwind = rust
                .llvm_libunwind
885 886
                .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"))
                .unwrap_or_default();
887
            set(&mut config.backtrace, rust.backtrace);
888
            set(&mut config.channel, rust.channel);
889
            config.description = rust.description;
890
            set(&mut config.rust_dist_src, rust.dist_src);
O
Oliver Schneider 已提交
891
            set(&mut config.verbose_tests, rust.verbose_tests);
892 893 894 895
            // in the case "false" is set explicitly, do not overwrite the command line args
            if let Some(true) = rust.incremental {
                config.incremental = true;
            }
896
            set(&mut config.use_lld, rust.use_lld);
897
            set(&mut config.lld_enabled, rust.lld);
898
            set(&mut config.llvm_tools_enabled, rust.llvm_tools);
899
            config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
900 901 902
            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);
903
            set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
J
John Kåre Alsaker 已提交
904
            set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
905
            set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
906
            config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
907
            set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
908
            set(&mut config.control_flow_guard, rust.control_flow_guard);
A
Alex Crichton 已提交
909

910
            if let Some(ref backends) = rust.codegen_backends {
M
Mark Rousskov 已提交
911 912
                config.rust_codegen_backends =
                    backends.iter().map(|s| INTERNER.intern_str(s)).collect();
913 914
            }

915 916
            config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
            config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
917 918
            config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
            config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
919
            config.download_rustc = env::var("BOOTSTRAP_DOWNLOAD_RUSTC").as_deref() == Ok("1");
920 921 922
        } else {
            config.rust_profile_use = flags.rust_profile_use;
            config.rust_profile_generate = flags.rust_profile_generate;
A
Alex Crichton 已提交
923 924
        }

925
        if let Some(t) = toml.target {
A
Alex Crichton 已提交
926
            for (triple, cfg) in t {
927
                let mut target = Target::from_triple(&triple);
A
Alex Crichton 已提交
928 929

                if let Some(ref s) = cfg.llvm_config {
930
                    target.llvm_config = Some(config.src.join(s));
A
Alex Crichton 已提交
931
                }
932 933 934
                if let Some(ref s) = cfg.llvm_filecheck {
                    target.llvm_filecheck = Some(config.src.join(s));
                }
A
Alex Crichton 已提交
935
                if let Some(ref s) = cfg.android_ndk {
936
                    target.ndk = Some(config.src.join(s));
A
Alex Crichton 已提交
937
                }
938 939 940
                if let Some(s) = cfg.no_std {
                    target.no_std = s;
                }
941 942 943 944 945
                target.cc = cfg.cc.map(PathBuf::from);
                target.cxx = cfg.cxx.map(PathBuf::from);
                target.ar = cfg.ar.map(PathBuf::from);
                target.ranlib = cfg.ranlib.map(PathBuf::from);
                target.linker = cfg.linker.map(PathBuf::from);
946
                target.crt_static = cfg.crt_static;
947 948 949 950
                target.musl_root = cfg.musl_root.map(PathBuf::from);
                target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
                target.wasi_root = cfg.wasi_root.map(PathBuf::from);
                target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
951 952
                target.sanitizers = cfg.sanitizers;
                target.profiler = cfg.profiler;
A
Alex Crichton 已提交
953

954
                config.target_config.insert(TargetSelection::from_user(&triple), target);
A
Alex Crichton 已提交
955 956 957
            }
        }

958 959 960 961 962 963 964 965 966 967 968 969 970 971
        if config.llvm_from_ci {
            let triple = &config.build.triple;
            let mut build_target = config
                .target_config
                .entry(config.build)
                .or_insert_with(|| Target::from_triple(&triple));

            check_ci_llvm!(build_target.llvm_config);
            check_ci_llvm!(build_target.llvm_filecheck);
            let ci_llvm_bin = config.out.join(&*config.build.triple).join("ci-llvm/bin");
            build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build)));
            build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build)));
        }

972 973 974
        if let Some(t) = toml.dist {
            config.dist_sign_folder = t.sign_folder.map(PathBuf::from);
            config.dist_upload_addr = t.upload_addr;
975
            config.dist_compression_formats = t.compression_formats;
976
            set(&mut config.rust_dist_src, t.src_tarball);
977
            set(&mut config.missing_tools, t.missing_tools);
978 979
        }

980 981 982 983 984 985 986 987 988 989 990 991
        config.initial_rustfmt = config.initial_rustfmt.or_else({
            let build = config.build;
            let initial_rustc = &config.initial_rustc;

            move || {
                // Cargo does not provide a RUSTFMT environment variable, so we
                // synthesize it manually.
                let rustfmt = initial_rustc.with_file_name(exe("rustfmt", build));

                if rustfmt.exists() { Some(rustfmt) } else { None }
            }
        });
992

993 994
        // Now that we've reached the end of our configuration, infer the
        // default values for all options that we haven't otherwise stored yet.
995

996
        config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false);
997
        config.llvm_assertions = llvm_assertions.unwrap_or(false);
998
        config.llvm_tests = llvm_tests.unwrap_or(false);
999
        config.llvm_plugins = llvm_plugins.unwrap_or(false);
1000
        config.rust_optimize = optimize.unwrap_or(true);
1001

1002 1003
        let default = debug == Some(true);
        config.rust_debug_assertions = debug_assertions.unwrap_or(default);
1004 1005
        config.rust_debug_assertions_std =
            debug_assertions_std.unwrap_or(config.rust_debug_assertions);
1006
        config.rust_overflow_checks = overflow_checks.unwrap_or(default);
1007 1008
        config.rust_overflow_checks_std =
            overflow_checks_std.unwrap_or(config.rust_overflow_checks);
1009

G
Gus Wynn 已提交
1010 1011
        config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions);

1012
        let with_defaults = |debuginfo_level_specific: Option<u32>| {
M
Mark Rousskov 已提交
1013
            debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
1014
                1
M
Mark Rousskov 已提交
1015 1016 1017
            } else {
                0
            })
1018 1019 1020 1021
        };
        config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
        config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
        config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
1022
        config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0);
1023

1024 1025 1026
        let default = config.channel == "dev";
        config.ignore_git = ignore_git.unwrap_or(default);

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
        let download_rustc = config.download_rustc;
        // See https://github.com/rust-lang/compiler-team/issues/326
        config.stage = match config.cmd {
            Subcommand::Check { .. } => flags.stage.or(build.check_stage).unwrap_or(0),
            // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden.
            Subcommand::Doc { .. } => {
                flags.stage.or(build.doc_stage).unwrap_or(if download_rustc { 2 } else { 0 })
            }
            Subcommand::Build { .. } => {
                flags.stage.or(build.build_stage).unwrap_or(if download_rustc { 2 } else { 1 })
            }
            Subcommand::Test { .. } => {
                flags.stage.or(build.test_stage).unwrap_or(if download_rustc { 2 } else { 1 })
            }
            Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2),
            Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2),
            Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2),
            // These are all bootstrap tools, which don't depend on the compiler.
            // The stage we pass shouldn't matter, but use 0 just in case.
            Subcommand::Clean { .. }
            | Subcommand::Clippy { .. }
            | Subcommand::Fix { .. }
            | Subcommand::Run { .. }
            | Subcommand::Setup { .. }
            | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
        };

        // CI should always run stage 2 builds, unless it specifically states otherwise
        #[cfg(not(test))]
        if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
            match config.cmd {
                Subcommand::Test { .. }
                | Subcommand::Doc { .. }
                | Subcommand::Build { .. }
                | Subcommand::Bench { .. }
                | Subcommand::Dist { .. }
                | Subcommand::Install { .. } => {
                    assert_eq!(
                        config.stage, 2,
                        "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`",
                        config.stage,
                    );
                }
                Subcommand::Clean { .. }
                | Subcommand::Check { .. }
                | Subcommand::Clippy { .. }
                | Subcommand::Fix { .. }
                | Subcommand::Run { .. }
                | Subcommand::Setup { .. }
                | Subcommand::Format { .. } => {}
            }
        }

1080
        config
1081
    }
1082

1083 1084
    /// Try to find the relative path of `bindir`, otherwise return it in full.
    pub fn bindir_relative(&self) -> &Path {
1085
        let bindir = &self.bindir;
1086
        if bindir.is_absolute() {
1087
            // Try to make it relative to the prefix.
1088 1089 1090 1091 1092
            if let Some(prefix) = &self.prefix {
                if let Ok(stripped) = bindir.strip_prefix(prefix) {
                    return stripped;
                }
            }
1093
        }
1094
        bindir
1095 1096
    }

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
    /// Try to find the relative path of `libdir`.
    pub fn libdir_relative(&self) -> Option<&Path> {
        let libdir = self.libdir.as_ref()?;
        if libdir.is_relative() {
            Some(libdir)
        } else {
            // Try to make it relative to the prefix.
            libdir.strip_prefix(self.prefix.as_ref()?).ok()
        }
    }

1108 1109 1110 1111 1112 1113 1114
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
B
bjorn3 已提交
1115

1116
    pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
1117
        self.target_config.get(&target).map(|t| t.sanitizers).flatten().unwrap_or(self.sanitizers)
1118 1119 1120
    }

    pub fn any_sanitizers_enabled(&self) -> bool {
1121
        self.target_config.values().any(|t| t.sanitizers == Some(true)) || self.sanitizers
1122 1123 1124
    }

    pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
1125
        self.target_config.get(&target).map(|t| t.profiler).flatten().unwrap_or(self.profiler)
1126 1127 1128
    }

    pub fn any_profiler_enabled(&self) -> bool {
1129
        self.target_config.values().any(|t| t.profiler == Some(true)) || self.profiler
1130 1131
    }

B
bjorn3 已提交
1132 1133 1134
    pub fn llvm_enabled(&self) -> bool {
        self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
    }
1135 1136 1137 1138

    pub fn submodules(&self, rust_info: &GitInfo) -> bool {
        self.submodules.unwrap_or(rust_info.is_git())
    }
A
Alex Crichton 已提交
1139 1140 1141 1142 1143 1144 1145
}

fn set<T>(field: &mut T, val: Option<T>) {
    if let Some(v) = val {
        *field = v;
    }
}
1146 1147 1148 1149 1150 1151 1152

fn threads_from_config(v: u32) -> u32 {
    match v {
        0 => num_cpus::get() as u32,
        n => n,
    }
}