config.rs 41.4 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_plugins: bool,
A
Alex Crichton 已提交
94
    pub llvm_optimize: bool,
95
    pub llvm_thin_lto: bool,
96
    pub llvm_release_debuginfo: bool,
A
Alex Crichton 已提交
97 98
    pub llvm_version_check: bool,
    pub llvm_static_stdcpp: bool,
99
    pub llvm_link_shared: bool,
100
    pub llvm_clang_cl: Option<String>,
101
    pub llvm_targets: Option<String>,
102
    pub llvm_experimental_targets: Option<String>,
103
    pub llvm_link_jobs: Option<u32>,
104
    pub llvm_version_suffix: Option<String>,
105
    pub llvm_use_linker: Option<String>,
106 107
    pub llvm_allow_old_toolchain: bool,
    pub llvm_polly: bool,
108
    pub llvm_clang: bool,
109
    pub llvm_from_ci: bool,
A
Alex Crichton 已提交
110

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

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

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

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

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

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

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

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

    // These are either the stage0 downloaded binaries or the locally installed ones.
    pub initial_cargo: PathBuf,
    pub initial_rustc: PathBuf,
A
Adam Perry 已提交
194
    pub initial_rustfmt: Option<PathBuf>,
195
    pub out: PathBuf,
A
Alex Crichton 已提交
196 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
#[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)),
        }
    }
}

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

308 309 310
impl Target {
    pub fn from_triple(triple: &str) -> Self {
        let mut target: Self = Default::default();
311
        if triple.contains("-none") || triple.contains("nvptx") {
312 313 314 315 316
            target.no_std = true;
        }
        target
    }
}
A
Alex Crichton 已提交
317 318 319 320 321
/// 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 已提交
322
#[derive(Deserialize, Default)]
323
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
A
Alex Crichton 已提交
324
struct TomlConfig {
J
Joshua Nelson 已提交
325
    changelog_seen: Option<usize>,
A
Alex Crichton 已提交
326
    build: Option<Build>,
J
Jeremy Soller 已提交
327
    install: Option<Install>,
A
Alex Crichton 已提交
328 329 330
    llvm: Option<Llvm>,
    rust: Option<Rust>,
    target: Option<HashMap<String, TomlTarget>>,
331
    dist: Option<Dist>,
332 333 334 335
    profile: Option<String>,
}

impl Merge for TomlConfig {
J
Joshua Nelson 已提交
336 337 338 339
    fn merge(
        &mut self,
        TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self,
    ) {
340 341 342 343 344 345 346 347
        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);
                }
            }
348
        }
349 350 351 352 353 354 355
        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 已提交
356 357 358
}

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

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

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

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

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

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

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

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

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

A
Adam Perry 已提交
554 555 556 557 558
    /// 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()
    }

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

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

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

        config
    }

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

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

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

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

626
            let contents = t!(fs::read_to_string(file), "`include` config not found");
627 628 629 630 631
            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 已提交
632
                }
633 634 635
            }
        };

636
        let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
637 638 639 640 641
        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");
642
            include_path.push(format!("config.{}.toml", include));
643
            let included_toml = get_toml(&include_path);
644 645
            toml.merge(included_toml);
        }
A
Alex Crichton 已提交
646

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

652
        let build = toml.build.unwrap_or_default();
653

654
        config.hosts = if let Some(arg_host) = flags.host {
655 656 657 658 659 660
            arg_host
        } else if let Some(file_host) = build.host {
            file_host.iter().map(|h| TargetSelection::from_user(h)).collect()
        } else {
            vec![config.build]
        };
661
        config.targets = if let Some(arg_target) = flags.target {
662 663 664 665 666 667 668 669
            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()
        };
670

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

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

700 701 702 703 704 705 706 707
        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 已提交
708 709
        }

710 711 712 713 714
        // 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;

715 716 717
        // 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;
718
        let mut llvm_plugins = None;
719 720
        let mut debug = None;
        let mut debug_assertions = None;
721
        let mut debug_assertions_std = None;
722 723
        let mut overflow_checks = None;
        let mut overflow_checks_std = None;
G
Gus Wynn 已提交
724
        let mut debug_logging = None;
725 726 727 728 729
        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;
730
        let mut optimize = None;
731
        let mut ignore_git = None;
732

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

            config.llvm_cflags = llvm.cflags.clone();
            config.llvm_cxxflags = llvm.cxxflags.clone();
            config.llvm_ldflags = llvm.ldflags.clone();
760
            set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
761
            config.llvm_use_linker = llvm.use_linker.clone();
762 763
            config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.unwrap_or(false);
            config.llvm_polly = llvm.polly.unwrap_or(false);
764
            config.llvm_clang = llvm.clang.unwrap_or(false);
765 766 767
            config.llvm_from_ci = match llvm.download_ci_llvm {
                Some(StringOrBool::String(s)) => {
                    assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
768 769 770 771 772 773 774 775 776 777 778 779 780 781
                    // This is currently all tier 1 targets (since others may not have CI artifacts)
                    // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
                    // FIXME: this is duplicated in bootstrap.py
                    let supported_platforms = [
                        "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",
                    ];
                    supported_platforms.contains(&&*config.build.triple)
782 783 784 785
                }
                Some(StringOrBool::Bool(b)) => b,
                None => false,
            };
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809

            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);
810
                check_ci_llvm!(llvm.polly);
811 812
                check_ci_llvm!(llvm.clang);
                check_ci_llvm!(llvm.plugins);
813

814 815
                // CI-built LLVM can be either dynamic or static.
                let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm");
816 817 818 819 820 821 822 823 824 825
                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"
                };
826 827 828 829 830 831
            }

            if config.llvm_thin_lto {
                // If we're building with ThinLTO on, we want to link to LLVM
                // shared, to avoid re-doing ThinLTO (which happens in the link
                // step) with each stage.
832 833 834 835 836
                assert_ne!(
                    llvm.link_shared,
                    Some(false),
                    "setting link-shared=false is incompatible with thin-lto=true"
                );
837
                config.llvm_link_shared = true;
838
            }
A
Alex Crichton 已提交
839
        }
J
Jeremy Soller 已提交
840

841
        if let Some(rust) = toml.rust {
842 843
            debug = rust.debug;
            debug_assertions = rust.debug_assertions;
844
            debug_assertions_std = rust.debug_assertions_std;
845 846
            overflow_checks = rust.overflow_checks;
            overflow_checks_std = rust.overflow_checks_std;
G
Gus Wynn 已提交
847
            debug_logging = rust.debug_logging;
848 849 850 851 852
            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;
853
            config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
854
            optimize = rust.optimize;
855
            ignore_git = rust.ignore_git;
856
            set(&mut config.rust_new_symbol_mangling, rust.new_symbol_mangling);
857
            set(&mut config.rust_optimize_tests, rust.optimize_tests);
858
            set(&mut config.codegen_tests, rust.codegen_tests);
A
Alex Crichton 已提交
859
            set(&mut config.rust_rpath, rust.rpath);
860
            set(&mut config.jemalloc, rust.jemalloc);
861
            set(&mut config.test_compare_mode, rust.test_compare_mode);
862 863
            config.llvm_libunwind = rust
                .llvm_libunwind
864 865
                .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"))
                .unwrap_or_default();
866
            set(&mut config.backtrace, rust.backtrace);
867
            set(&mut config.channel, rust.channel);
868
            config.description = rust.description;
869
            set(&mut config.rust_dist_src, rust.dist_src);
O
Oliver Schneider 已提交
870
            set(&mut config.verbose_tests, rust.verbose_tests);
871 872 873 874
            // in the case "false" is set explicitly, do not overwrite the command line args
            if let Some(true) = rust.incremental {
                config.incremental = true;
            }
875
            set(&mut config.use_lld, rust.use_lld);
876
            set(&mut config.lld_enabled, rust.lld);
877
            set(&mut config.llvm_tools_enabled, rust.llvm_tools);
878
            config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
879 880 881
            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);
882
            set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
J
John Kåre Alsaker 已提交
883
            set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
884
            set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
885
            config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
886
            set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
887
            set(&mut config.control_flow_guard, rust.control_flow_guard);
A
Alex Crichton 已提交
888

889
            if let Some(ref backends) = rust.codegen_backends {
M
Mark Rousskov 已提交
890 891
                config.rust_codegen_backends =
                    backends.iter().map(|s| INTERNER.intern_str(s)).collect();
892 893
            }

894 895
            config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
            config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
896 897
            config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
            config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
898
            config.download_rustc = env::var("BOOTSTRAP_DOWNLOAD_RUSTC").as_deref() == Ok("1");
899 900 901
        } else {
            config.rust_profile_use = flags.rust_profile_use;
            config.rust_profile_generate = flags.rust_profile_generate;
A
Alex Crichton 已提交
902 903
        }

904
        if let Some(t) = toml.target {
A
Alex Crichton 已提交
905
            for (triple, cfg) in t {
906
                let mut target = Target::from_triple(&triple);
A
Alex Crichton 已提交
907 908

                if let Some(ref s) = cfg.llvm_config {
909
                    target.llvm_config = Some(config.src.join(s));
A
Alex Crichton 已提交
910
                }
911 912 913
                if let Some(ref s) = cfg.llvm_filecheck {
                    target.llvm_filecheck = Some(config.src.join(s));
                }
A
Alex Crichton 已提交
914
                if let Some(ref s) = cfg.android_ndk {
915
                    target.ndk = Some(config.src.join(s));
A
Alex Crichton 已提交
916
                }
917 918 919
                if let Some(s) = cfg.no_std {
                    target.no_std = s;
                }
920 921 922 923 924
                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);
925
                target.crt_static = cfg.crt_static;
926 927 928 929
                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);
930 931
                target.sanitizers = cfg.sanitizers;
                target.profiler = cfg.profiler;
A
Alex Crichton 已提交
932

933
                config.target_config.insert(TargetSelection::from_user(&triple), target);
A
Alex Crichton 已提交
934 935 936
            }
        }

937 938 939 940 941 942 943 944 945 946 947 948 949 950
        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)));
        }

951 952 953
        if let Some(t) = toml.dist {
            config.dist_sign_folder = t.sign_folder.map(PathBuf::from);
            config.dist_upload_addr = t.upload_addr;
954
            config.dist_compression_formats = t.compression_formats;
955
            set(&mut config.rust_dist_src, t.src_tarball);
956
            set(&mut config.missing_tools, t.missing_tools);
957 958
        }

959 960 961 962 963 964 965 966 967 968 969 970
        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 }
            }
        });
971

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

975
        config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false);
976
        config.llvm_assertions = llvm_assertions.unwrap_or(false);
977
        config.llvm_plugins = llvm_plugins.unwrap_or(false);
978
        config.rust_optimize = optimize.unwrap_or(true);
979

980 981
        let default = debug == Some(true);
        config.rust_debug_assertions = debug_assertions.unwrap_or(default);
982 983
        config.rust_debug_assertions_std =
            debug_assertions_std.unwrap_or(config.rust_debug_assertions);
984 985
        config.rust_overflow_checks = overflow_checks.unwrap_or(default);
        config.rust_overflow_checks_std = overflow_checks_std.unwrap_or(default);
986

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

989
        let with_defaults = |debuginfo_level_specific: Option<u32>| {
M
Mark Rousskov 已提交
990
            debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
991
                1
M
Mark Rousskov 已提交
992 993 994
            } else {
                0
            })
995 996 997 998
        };
        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);
999
        config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0);
1000

1001 1002 1003
        let default = config.channel == "dev";
        config.ignore_git = ignore_git.unwrap_or(default);

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 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
        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 { .. } => {}
            }
        }

1057
        config
1058
    }
1059

1060 1061
    /// Try to find the relative path of `bindir`, otherwise return it in full.
    pub fn bindir_relative(&self) -> &Path {
1062
        let bindir = &self.bindir;
1063
        if bindir.is_absolute() {
1064
            // Try to make it relative to the prefix.
1065 1066 1067 1068 1069
            if let Some(prefix) = &self.prefix {
                if let Ok(stripped) = bindir.strip_prefix(prefix) {
                    return stripped;
                }
            }
1070
        }
1071
        bindir
1072 1073
    }

1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
    /// 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()
        }
    }

1085 1086 1087 1088 1089 1090 1091
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

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

1093
    pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
1094
        self.target_config.get(&target).map(|t| t.sanitizers).flatten().unwrap_or(self.sanitizers)
1095 1096 1097
    }

    pub fn any_sanitizers_enabled(&self) -> bool {
1098
        self.target_config.values().any(|t| t.sanitizers == Some(true)) || self.sanitizers
1099 1100 1101
    }

    pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
1102
        self.target_config.get(&target).map(|t| t.profiler).flatten().unwrap_or(self.profiler)
1103 1104 1105
    }

    pub fn any_profiler_enabled(&self) -> bool {
1106
        self.target_config.values().any(|t| t.profiler == Some(true)) || self.profiler
1107 1108
    }

B
bjorn3 已提交
1109 1110 1111
    pub fn llvm_enabled(&self) -> bool {
        self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
    }
1112 1113 1114 1115

    pub fn submodules(&self, rust_info: &GitInfo) -> bool {
        self.submodules.unwrap_or(rust_info.is_git())
    }
A
Alex Crichton 已提交
1116 1117 1118 1119 1120 1121 1122
}

fn set<T>(field: &mut T, val: Option<T>) {
    if let Some(v) = val {
        *field = v;
    }
}
1123 1124 1125 1126 1127 1128 1129

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