1 //! Serialized configuration of a build.
3 //! This module implements parsing `config.toml` configuration files to tweak
4 //! how the build runs.
6 use std
::cell
::{Cell, RefCell}
;
8 use std
::collections
::{HashMap, HashSet}
;
12 use std
::path
::{Path, PathBuf}
;
13 use std
::process
::Command
;
14 use std
::str::FromStr
;
16 use crate::builder
::TaskPath
;
17 use crate::cache
::{Interned, INTERNER}
;
18 use crate::cc_detect
::{ndk_compiler, Language}
;
19 use crate::channel
::{self, GitInfo}
;
20 pub use crate::flags
::Subcommand
;
21 use crate::flags
::{Color, Flags}
;
22 use crate::util
::{exe, output, t}
;
23 use once_cell
::sync
::OnceCell
;
24 use serde
::{Deserialize, Deserializer}
;
26 macro_rules
! check_ci_llvm
{
30 "setting {} is incompatible with download-ci-llvm.",
36 #[derive(Clone, Default)]
38 /// This isn't a dry run.
41 /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done.
43 /// This is a dry run enabled by the `--dry-run` flag.
47 /// Global configuration for the entire build and/or bootstrap.
49 /// This structure is derived from a combination of both `config.toml` and
50 /// `config.mk`. As of the time of this writing it's unlikely that `config.toml`
51 /// is used all that much, so this is primarily filled out by `config.mk` which
52 /// is generated from `./configure`.
54 /// Note that this structure is not decoded directly into, but rather it is
55 /// filled out from the decoded forms of the structs below. For documentation
56 /// each field, see the corresponding fields in
57 /// `config.toml.example`.
59 #[cfg_attr(test, derive(Clone))]
61 pub changelog_seen
: Option
<usize>,
62 pub ccache
: Option
<String
>,
63 /// Call Build::ninja() instead of this.
64 pub ninja_in_file
: bool
,
66 pub submodules
: Option
<bool
>,
67 pub compiler_docs
: bool
,
68 pub docs_minification
: bool
,
70 pub locked_deps
: bool
,
72 pub target_config
: HashMap
<TargetSelection
, Target
>,
73 pub full_bootstrap
: bool
,
75 pub tools
: Option
<HashSet
<String
>>,
79 pub exclude
: Vec
<TaskPath
>,
80 pub include_default_paths
: bool
,
81 pub rustc_error_format
: Option
<String
>,
82 pub json_output
: bool
,
83 pub test_compare_mode
: bool
,
85 pub patch_binaries_for_nix
: bool
,
86 pub stage0_metadata
: Stage0Metadata
,
88 pub on_fail
: Option
<String
>,
90 pub keep_stage
: Vec
<u32>,
91 pub keep_stage_std
: Vec
<u32>,
93 /// defaults to `config.toml`
94 pub config
: Option
<PathBuf
>,
95 pub jobs
: Option
<u32>,
97 pub incremental
: bool
,
99 /// `None` if we shouldn't download CI compiler artifacts, or the commit to download if we should.
101 download_rustc_commit
: Option
<String
>,
103 pub download_rustc_commit
: Option
<String
>,
105 pub deny_warnings
: bool
,
106 pub backtrace_on_ice
: bool
,
108 // llvm codegen options
109 pub llvm_skip_rebuild
: bool
,
110 pub llvm_assertions
: bool
,
111 pub llvm_tests
: bool
,
112 pub llvm_plugins
: bool
,
113 pub llvm_optimize
: bool
,
114 pub llvm_thin_lto
: bool
,
115 pub llvm_release_debuginfo
: bool
,
116 pub llvm_version_check
: bool
,
117 pub llvm_static_stdcpp
: bool
,
118 /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
120 llvm_link_shared
: Cell
<Option
<bool
>>,
122 pub llvm_link_shared
: Cell
<Option
<bool
>>,
123 pub llvm_clang_cl
: Option
<String
>,
124 pub llvm_targets
: Option
<String
>,
125 pub llvm_experimental_targets
: Option
<String
>,
126 pub llvm_link_jobs
: Option
<u32>,
127 pub llvm_version_suffix
: Option
<String
>,
128 pub llvm_use_linker
: Option
<String
>,
129 pub llvm_allow_old_toolchain
: bool
,
130 pub llvm_polly
: bool
,
131 pub llvm_clang
: bool
,
132 pub llvm_from_ci
: bool
,
133 pub llvm_build_config
: HashMap
<String
, String
>,
136 pub lld_enabled
: bool
,
137 pub llvm_tools_enabled
: bool
,
139 pub llvm_cflags
: Option
<String
>,
140 pub llvm_cxxflags
: Option
<String
>,
141 pub llvm_ldflags
: Option
<String
>,
142 pub llvm_use_libcxx
: bool
,
144 // rust codegen options
145 pub rust_optimize
: bool
,
146 pub rust_codegen_units
: Option
<u32>,
147 pub rust_codegen_units_std
: Option
<u32>,
148 pub rust_debug_assertions
: bool
,
149 pub rust_debug_assertions_std
: bool
,
150 pub rust_overflow_checks
: bool
,
151 pub rust_overflow_checks_std
: bool
,
152 pub rust_debug_logging
: bool
,
153 pub rust_debuginfo_level_rustc
: u32,
154 pub rust_debuginfo_level_std
: u32,
155 pub rust_debuginfo_level_tools
: u32,
156 pub rust_debuginfo_level_tests
: u32,
157 pub rust_split_debuginfo
: SplitDebuginfo
,
158 pub rust_rpath
: bool
,
159 pub rustc_parallel
: bool
,
160 pub rustc_default_linker
: Option
<String
>,
161 pub rust_optimize_tests
: bool
,
162 pub rust_dist_src
: bool
,
163 pub rust_codegen_backends
: Vec
<Interned
<String
>>,
164 pub rust_verify_llvm_ir
: bool
,
165 pub rust_thin_lto_import_instr_limit
: Option
<u32>,
166 pub rust_remap_debuginfo
: bool
,
167 pub rust_new_symbol_mangling
: Option
<bool
>,
168 pub rust_profile_use
: Option
<String
>,
169 pub rust_profile_generate
: Option
<String
>,
170 pub rust_lto
: RustcLto
,
171 pub llvm_profile_use
: Option
<String
>,
172 pub llvm_profile_generate
: bool
,
173 pub llvm_libunwind_default
: Option
<LlvmLibunwind
>,
174 pub llvm_bolt_profile_generate
: bool
,
175 pub llvm_bolt_profile_use
: Option
<String
>,
177 pub build
: TargetSelection
,
178 pub hosts
: Vec
<TargetSelection
>,
179 pub targets
: Vec
<TargetSelection
>,
180 pub local_rebuild
: bool
,
182 pub control_flow_guard
: bool
,
185 pub dist_sign_folder
: Option
<PathBuf
>,
186 pub dist_upload_addr
: Option
<String
>,
187 pub dist_compression_formats
: Option
<Vec
<String
>>,
190 pub backtrace
: bool
, // support for RUST_BACKTRACE
193 pub low_priority
: bool
,
195 pub description
: Option
<String
>,
196 pub verbose_tests
: bool
,
197 pub save_toolstates
: Option
<PathBuf
>,
198 pub print_step_timings
: bool
,
199 pub print_step_rusage
: bool
,
200 pub missing_tools
: bool
,
202 // Fallback musl-root for all targets
203 pub musl_root
: Option
<PathBuf
>,
204 pub prefix
: Option
<PathBuf
>,
205 pub sysconfdir
: Option
<PathBuf
>,
206 pub datadir
: Option
<PathBuf
>,
207 pub docdir
: Option
<PathBuf
>,
209 pub libdir
: Option
<PathBuf
>,
210 pub mandir
: Option
<PathBuf
>,
211 pub codegen_tests
: bool
,
212 pub nodejs
: Option
<PathBuf
>,
213 pub npm
: Option
<PathBuf
>,
214 pub gdb
: Option
<PathBuf
>,
215 pub python
: Option
<PathBuf
>,
216 pub reuse
: Option
<PathBuf
>,
217 pub cargo_native_static
: bool
,
218 pub configure_args
: Vec
<String
>,
220 // These are either the stage0 downloaded binaries or the locally installed ones.
221 pub initial_cargo
: PathBuf
,
222 pub initial_rustc
: PathBuf
,
224 initial_rustfmt
: RefCell
<RustfmtState
>,
226 pub initial_rustfmt
: RefCell
<RustfmtState
>,
228 pub rust_info
: channel
::GitInfo
,
231 #[derive(Default, Deserialize)]
232 #[cfg_attr(test, derive(Clone))]
233 pub struct Stage0Metadata
{
234 pub config
: Stage0Config
,
235 pub checksums_sha256
: HashMap
<String
, String
>,
236 pub rustfmt
: Option
<RustfmtMetadata
>,
238 #[derive(Default, Deserialize)]
239 #[cfg_attr(test, derive(Clone))]
240 pub struct Stage0Config
{
241 pub dist_server
: String
,
242 pub artifacts_server
: String
,
243 pub artifacts_with_llvm_assertions_server
: String
,
244 pub git_merge_commit_email
: String
,
245 pub nightly_branch
: String
,
247 #[derive(Default, Deserialize)]
248 #[cfg_attr(test, derive(Clone))]
249 pub struct RustfmtMetadata
{
254 #[derive(Clone, Debug)]
255 pub enum RustfmtState
{
256 SystemToolchain(PathBuf
),
262 impl Default
for RustfmtState
{
263 fn default() -> Self {
264 RustfmtState
::LazyEvaluated
268 #[derive(Debug, Clone, Copy, PartialEq)]
269 pub enum LlvmLibunwind
{
275 impl Default
for LlvmLibunwind
{
276 fn default() -> Self {
281 impl FromStr
for LlvmLibunwind
{
284 fn from_str(value
: &str) -> Result
<Self, Self::Err
> {
286 "no" => Ok(Self::No
),
287 "in-tree" => Ok(Self::InTree
),
288 "system" => Ok(Self::System
),
289 invalid
=> Err(format
!("Invalid value '{}' for rust.llvm-libunwind config.", invalid
)),
294 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
295 pub enum SplitDebuginfo
{
301 impl Default
for SplitDebuginfo
{
302 fn default() -> Self {
307 impl std
::str::FromStr
for SplitDebuginfo
{
310 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
312 "packed" => Ok(SplitDebuginfo
::Packed
),
313 "unpacked" => Ok(SplitDebuginfo
::Unpacked
),
314 "off" => Ok(SplitDebuginfo
::Off
),
320 impl SplitDebuginfo
{
321 /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
322 /// `rust.split-debuginfo` in `config.toml.example`.
323 fn default_for_platform(target
: &str) -> Self {
324 if target
.contains("apple") {
325 SplitDebuginfo
::Unpacked
326 } else if target
.contains("windows") {
327 SplitDebuginfo
::Packed
334 /// LTO mode used for compiling rustc itself.
335 #[derive(Default, Clone)]
343 impl std
::str::FromStr
for RustcLto
{
346 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
348 "thin-local" => Ok(RustcLto
::ThinLocal
),
349 "thin" => Ok(RustcLto
::Thin
),
350 "fat" => Ok(RustcLto
::Fat
),
351 _
=> Err(format
!("Invalid value for rustc LTO: {}", s
)),
356 #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
357 pub struct TargetSelection
{
358 pub triple
: Interned
<String
>,
359 file
: Option
<Interned
<String
>>,
362 impl TargetSelection
{
363 pub fn from_user(selection
: &str) -> Self {
364 let path
= Path
::new(selection
);
366 let (triple
, file
) = if path
.exists() {
369 .expect("Target specification file has no file stem")
371 .expect("Target specification file stem is not UTF-8");
373 (triple
, Some(selection
))
378 let triple
= INTERNER
.intern_str(triple
);
379 let file
= file
.map(|f
| INTERNER
.intern_str(f
));
381 Self { triple, file }
384 pub fn rustc_target_arg(&self) -> &str {
385 self.file
.as_ref().unwrap_or(&self.triple
)
388 pub fn contains(&self, needle
: &str) -> bool
{
389 self.triple
.contains(needle
)
392 pub fn starts_with(&self, needle
: &str) -> bool
{
393 self.triple
.starts_with(needle
)
396 pub fn ends_with(&self, needle
: &str) -> bool
{
397 self.triple
.ends_with(needle
)
401 impl fmt
::Display
for TargetSelection
{
402 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
403 write
!(f
, "{}", self.triple
)?
;
404 if let Some(file
) = self.file
{
405 write
!(f
, "({})", file
)?
;
411 impl fmt
::Debug
for TargetSelection
{
412 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
413 write
!(f
, "{}", self)
417 impl PartialEq
<&str> for TargetSelection
{
418 fn eq(&self, other
: &&str) -> bool
{
419 self.triple
== *other
423 /// Per-target configuration stored in the global configuration structure.
425 #[cfg_attr(test, derive(Clone))]
427 /// Some(path to llvm-config) if using an external LLVM.
428 pub llvm_config
: Option
<PathBuf
>,
429 pub llvm_has_rust_patches
: Option
<bool
>,
430 /// Some(path to FileCheck) if one was specified.
431 pub llvm_filecheck
: Option
<PathBuf
>,
432 pub llvm_libunwind
: Option
<LlvmLibunwind
>,
433 pub cc
: Option
<PathBuf
>,
434 pub cxx
: Option
<PathBuf
>,
435 pub ar
: Option
<PathBuf
>,
436 pub ranlib
: Option
<PathBuf
>,
437 pub default_linker
: Option
<PathBuf
>,
438 pub linker
: Option
<PathBuf
>,
439 pub ndk
: Option
<PathBuf
>,
440 pub sanitizers
: Option
<bool
>,
441 pub profiler
: Option
<bool
>,
442 pub crt_static
: Option
<bool
>,
443 pub musl_root
: Option
<PathBuf
>,
444 pub musl_libdir
: Option
<PathBuf
>,
445 pub wasi_root
: Option
<PathBuf
>,
446 pub qemu_rootfs
: Option
<PathBuf
>,
451 pub fn from_triple(triple
: &str) -> Self {
452 let mut target
: Self = Default
::default();
453 if triple
.contains("-none")
454 || triple
.contains("nvptx")
455 || triple
.contains("switch")
456 || triple
.contains("-uefi")
458 target
.no_std
= true;
463 /// Structure of the `config.toml` file that configuration is read from.
465 /// This structure uses `Decodable` to automatically decode a TOML configuration
466 /// file into this format, and then this is traversed and written into the above
467 /// `Config` structure.
468 #[derive(Deserialize, Default)]
469 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
471 changelog_seen
: Option
<usize>,
472 build
: Option
<Build
>,
473 install
: Option
<Install
>,
476 target
: Option
<HashMap
<String
, TomlTarget
>>,
478 profile
: Option
<String
>,
482 fn merge(&mut self, other
: Self);
485 impl Merge
for TomlConfig
{
488 TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }
: Self,
490 fn do_merge
<T
: Merge
>(x
: &mut Option
<T
>, y
: Option
<T
>) {
491 if let Some(new
) = y
{
492 if let Some(original
) = x
{
499 do_merge(&mut self.build
, build
);
500 do_merge(&mut self.install
, install
);
501 do_merge(&mut self.llvm
, llvm
);
502 do_merge(&mut self.rust
, rust
);
503 do_merge(&mut self.dist
, dist
);
504 assert
!(target
.is_none(), "merging target-specific config is not currently supported");
508 // We are using a decl macro instead of a derive proc macro here to reduce the compile time of
510 macro_rules
! define_config
{
511 ($
(#[$attr:meta])* struct $name:ident {
512 $
($field
:ident
: Option
<$field_ty
:ty
> = $field_key
:literal
,)*
516 $
($field
: Option
<$field_ty
>,)*
519 impl Merge
for $name
{
520 fn merge(&mut self, other
: Self) {
522 if !self.$field
.is_some() {
523 self.$field
= other
.$field
;
529 // The following is a trimmed version of what serde_derive generates. All parts not relevant
530 // for toml deserialization have been removed. This reduces the binary size and improves
531 // compile time of rustbuild.
532 impl<'de
> Deserialize
<'de
> for $name
{
533 fn deserialize
<D
>(deserializer
: D
) -> Result
<Self, D
::Error
>
535 D
: Deserializer
<'de
>,
538 impl<'de
> serde
::de
::Visitor
<'de
> for Field
{
540 fn expecting(&self, f
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
541 f
.write_str(concat
!("struct ", stringify
!($name
)))
545 fn visit_map
<A
>(self, mut map
: A
) -> Result
<Self::Value
, A
::Error
>
547 A
: serde
::de
::MapAccess
<'de
>,
549 $
(let mut $field
: Option
<$field_ty
> = None
;)*
550 while let Some(key
) =
551 match serde
::de
::MapAccess
::next_key
::<String
>(&mut map
) {
560 if $field
.is_some() {
561 return Err(<A
::Error
as serde
::de
::Error
>::duplicate_field(
565 $field
= match serde
::de
::MapAccess
::next_value
::<$field_ty
>(
568 Ok(val
) => Some(val
),
575 return Err(serde
::de
::Error
::unknown_field(key
, FIELDS
));
579 Ok($name { $($field),* }
)
582 const FIELDS
: &'
static [&'
static str] = &[
585 Deserializer
::deserialize_struct(
597 /// TOML representation of various global build decisions.
600 build
: Option
<String
> = "build",
601 host
: Option
<Vec
<String
>> = "host",
602 target
: Option
<Vec
<String
>> = "target",
603 build_dir
: Option
<String
> = "build-dir",
604 cargo
: Option
<String
> = "cargo",
605 rustc
: Option
<String
> = "rustc",
606 rustfmt
: Option
<PathBuf
> = "rustfmt",
607 docs
: Option
<bool
> = "docs",
608 compiler_docs
: Option
<bool
> = "compiler-docs",
609 docs_minification
: Option
<bool
> = "docs-minification",
610 submodules
: Option
<bool
> = "submodules",
611 gdb
: Option
<String
> = "gdb",
612 nodejs
: Option
<String
> = "nodejs",
613 npm
: Option
<String
> = "npm",
614 python
: Option
<String
> = "python",
615 reuse
: Option
<String
> = "reuse",
616 locked_deps
: Option
<bool
> = "locked-deps",
617 vendor
: Option
<bool
> = "vendor",
618 full_bootstrap
: Option
<bool
> = "full-bootstrap",
619 extended
: Option
<bool
> = "extended",
620 tools
: Option
<HashSet
<String
>> = "tools",
621 verbose
: Option
<usize> = "verbose",
622 sanitizers
: Option
<bool
> = "sanitizers",
623 profiler
: Option
<bool
> = "profiler",
624 cargo_native_static
: Option
<bool
> = "cargo-native-static",
625 low_priority
: Option
<bool
> = "low-priority",
626 configure_args
: Option
<Vec
<String
>> = "configure-args",
627 local_rebuild
: Option
<bool
> = "local-rebuild",
628 print_step_timings
: Option
<bool
> = "print-step-timings",
629 print_step_rusage
: Option
<bool
> = "print-step-rusage",
630 check_stage
: Option
<u32> = "check-stage",
631 doc_stage
: Option
<u32> = "doc-stage",
632 build_stage
: Option
<u32> = "build-stage",
633 test_stage
: Option
<u32> = "test-stage",
634 install_stage
: Option
<u32> = "install-stage",
635 dist_stage
: Option
<u32> = "dist-stage",
636 bench_stage
: Option
<u32> = "bench-stage",
637 patch_binaries_for_nix
: Option
<bool
> = "patch-binaries-for-nix",
638 metrics
: Option
<bool
> = "metrics",
643 /// TOML representation of various global install decisions.
645 prefix
: Option
<String
> = "prefix",
646 sysconfdir
: Option
<String
> = "sysconfdir",
647 docdir
: Option
<String
> = "docdir",
648 bindir
: Option
<String
> = "bindir",
649 libdir
: Option
<String
> = "libdir",
650 mandir
: Option
<String
> = "mandir",
651 datadir
: Option
<String
> = "datadir",
656 /// TOML representation of how the LLVM build is configured.
658 skip_rebuild
: Option
<bool
> = "skip-rebuild",
659 optimize
: Option
<bool
> = "optimize",
660 thin_lto
: Option
<bool
> = "thin-lto",
661 release_debuginfo
: Option
<bool
> = "release-debuginfo",
662 assertions
: Option
<bool
> = "assertions",
663 tests
: Option
<bool
> = "tests",
664 plugins
: Option
<bool
> = "plugins",
665 ccache
: Option
<StringOrBool
> = "ccache",
666 version_check
: Option
<bool
> = "version-check",
667 static_libstdcpp
: Option
<bool
> = "static-libstdcpp",
668 ninja
: Option
<bool
> = "ninja",
669 targets
: Option
<String
> = "targets",
670 experimental_targets
: Option
<String
> = "experimental-targets",
671 link_jobs
: Option
<u32> = "link-jobs",
672 link_shared
: Option
<bool
> = "link-shared",
673 version_suffix
: Option
<String
> = "version-suffix",
674 clang_cl
: Option
<String
> = "clang-cl",
675 cflags
: Option
<String
> = "cflags",
676 cxxflags
: Option
<String
> = "cxxflags",
677 ldflags
: Option
<String
> = "ldflags",
678 use_libcxx
: Option
<bool
> = "use-libcxx",
679 use_linker
: Option
<String
> = "use-linker",
680 allow_old_toolchain
: Option
<bool
> = "allow-old-toolchain",
681 polly
: Option
<bool
> = "polly",
682 clang
: Option
<bool
> = "clang",
683 download_ci_llvm
: Option
<StringOrBool
> = "download-ci-llvm",
684 build_config
: Option
<HashMap
<String
, String
>> = "build-config",
690 sign_folder
: Option
<String
> = "sign-folder",
691 gpg_password_file
: Option
<String
> = "gpg-password-file",
692 upload_addr
: Option
<String
> = "upload-addr",
693 src_tarball
: Option
<bool
> = "src-tarball",
694 missing_tools
: Option
<bool
> = "missing-tools",
695 compression_formats
: Option
<Vec
<String
>> = "compression-formats",
699 #[derive(Deserialize)]
706 impl Default
for StringOrBool
{
707 fn default() -> StringOrBool
{
708 StringOrBool
::Bool(false)
713 /// TOML representation of how the Rust build is configured.
715 optimize
: Option
<bool
> = "optimize",
716 debug
: Option
<bool
> = "debug",
717 codegen_units
: Option
<u32> = "codegen-units",
718 codegen_units_std
: Option
<u32> = "codegen-units-std",
719 debug_assertions
: Option
<bool
> = "debug-assertions",
720 debug_assertions_std
: Option
<bool
> = "debug-assertions-std",
721 overflow_checks
: Option
<bool
> = "overflow-checks",
722 overflow_checks_std
: Option
<bool
> = "overflow-checks-std",
723 debug_logging
: Option
<bool
> = "debug-logging",
724 debuginfo_level
: Option
<u32> = "debuginfo-level",
725 debuginfo_level_rustc
: Option
<u32> = "debuginfo-level-rustc",
726 debuginfo_level_std
: Option
<u32> = "debuginfo-level-std",
727 debuginfo_level_tools
: Option
<u32> = "debuginfo-level-tools",
728 debuginfo_level_tests
: Option
<u32> = "debuginfo-level-tests",
729 split_debuginfo
: Option
<String
> = "split-debuginfo",
730 run_dsymutil
: Option
<bool
> = "run-dsymutil",
731 backtrace
: Option
<bool
> = "backtrace",
732 incremental
: Option
<bool
> = "incremental",
733 parallel_compiler
: Option
<bool
> = "parallel-compiler",
734 default_linker
: Option
<String
> = "default-linker",
735 channel
: Option
<String
> = "channel",
736 description
: Option
<String
> = "description",
737 musl_root
: Option
<String
> = "musl-root",
738 rpath
: Option
<bool
> = "rpath",
739 verbose_tests
: Option
<bool
> = "verbose-tests",
740 optimize_tests
: Option
<bool
> = "optimize-tests",
741 codegen_tests
: Option
<bool
> = "codegen-tests",
742 ignore_git
: Option
<bool
> = "ignore-git",
743 dist_src
: Option
<bool
> = "dist-src",
744 save_toolstates
: Option
<String
> = "save-toolstates",
745 codegen_backends
: Option
<Vec
<String
>> = "codegen-backends",
746 lld
: Option
<bool
> = "lld",
747 use_lld
: Option
<bool
> = "use-lld",
748 llvm_tools
: Option
<bool
> = "llvm-tools",
749 deny_warnings
: Option
<bool
> = "deny-warnings",
750 backtrace_on_ice
: Option
<bool
> = "backtrace-on-ice",
751 verify_llvm_ir
: Option
<bool
> = "verify-llvm-ir",
752 thin_lto_import_instr_limit
: Option
<u32> = "thin-lto-import-instr-limit",
753 remap_debuginfo
: Option
<bool
> = "remap-debuginfo",
754 jemalloc
: Option
<bool
> = "jemalloc",
755 test_compare_mode
: Option
<bool
> = "test-compare-mode",
756 llvm_libunwind
: Option
<String
> = "llvm-libunwind",
757 control_flow_guard
: Option
<bool
> = "control-flow-guard",
758 new_symbol_mangling
: Option
<bool
> = "new-symbol-mangling",
759 profile_generate
: Option
<String
> = "profile-generate",
760 profile_use
: Option
<String
> = "profile-use",
761 // ignored; this is set from an env var set by bootstrap.py
762 download_rustc
: Option
<StringOrBool
> = "download-rustc",
763 lto
: Option
<String
> = "lto",
768 /// TOML representation of how each build target is configured.
770 cc
: Option
<String
> = "cc",
771 cxx
: Option
<String
> = "cxx",
772 ar
: Option
<String
> = "ar",
773 ranlib
: Option
<String
> = "ranlib",
774 default_linker
: Option
<PathBuf
> = "default-linker",
775 linker
: Option
<String
> = "linker",
776 llvm_config
: Option
<String
> = "llvm-config",
777 llvm_has_rust_patches
: Option
<bool
> = "llvm-has-rust-patches",
778 llvm_filecheck
: Option
<String
> = "llvm-filecheck",
779 llvm_libunwind
: Option
<String
> = "llvm-libunwind",
780 android_ndk
: Option
<String
> = "android-ndk",
781 sanitizers
: Option
<bool
> = "sanitizers",
782 profiler
: Option
<bool
> = "profiler",
783 crt_static
: Option
<bool
> = "crt-static",
784 musl_root
: Option
<String
> = "musl-root",
785 musl_libdir
: Option
<String
> = "musl-libdir",
786 wasi_root
: Option
<String
> = "wasi-root",
787 qemu_rootfs
: Option
<String
> = "qemu-rootfs",
788 no_std
: Option
<bool
> = "no-std",
793 pub fn default_opts() -> Config
{
794 let mut config
= Config
::default();
795 config
.llvm_optimize
= true;
796 config
.ninja_in_file
= true;
797 config
.llvm_version_check
= true;
798 config
.llvm_static_stdcpp
= false;
799 config
.backtrace
= true;
800 config
.rust_optimize
= true;
801 config
.rust_optimize_tests
= true;
802 config
.submodules
= None
;
804 config
.docs_minification
= true;
805 config
.rust_rpath
= true;
806 config
.channel
= "dev".to_string();
807 config
.codegen_tests
= true;
808 config
.rust_dist_src
= true;
809 config
.rust_codegen_backends
= vec
![INTERNER
.intern_str("llvm")];
810 config
.deny_warnings
= true;
811 config
.bindir
= "bin".into();
814 config
.build
= TargetSelection
::from_user(&env
!("BUILD_TRIPLE"));
816 let manifest_dir
= PathBuf
::from(env
!("CARGO_MANIFEST_DIR"));
817 // Undo `src/bootstrap`
818 config
.src
= manifest_dir
.parent().unwrap().parent().unwrap().to_owned();
819 config
.out
= PathBuf
::from("build");
824 pub fn parse(args
: &[String
]) -> Config
{
825 let flags
= Flags
::parse(&args
);
826 let mut config
= Config
::default_opts();
829 config
.exclude
= flags
.exclude
.into_iter().map(|path
| TaskPath
::parse(path
)).collect();
830 config
.include_default_paths
= flags
.include_default_paths
;
831 config
.rustc_error_format
= flags
.rustc_error_format
;
832 config
.json_output
= flags
.json_output
;
833 config
.on_fail
= flags
.on_fail
;
834 config
.jobs
= flags
.jobs
.map(threads_from_config
);
835 config
.cmd
= flags
.cmd
;
836 config
.incremental
= flags
.incremental
;
837 config
.dry_run
= if flags
.dry_run { DryRun::UserSelected }
else { DryRun::Disabled }
;
838 config
.keep_stage
= flags
.keep_stage
;
839 config
.keep_stage_std
= flags
.keep_stage_std
;
840 config
.color
= flags
.color
;
841 if let Some(value
) = flags
.deny_warnings
{
842 config
.deny_warnings
= value
;
844 config
.llvm_profile_use
= flags
.llvm_profile_use
;
845 config
.llvm_profile_generate
= flags
.llvm_profile_generate
;
846 config
.llvm_bolt_profile_generate
= flags
.llvm_bolt_profile_generate
;
847 config
.llvm_bolt_profile_use
= flags
.llvm_bolt_profile_use
;
849 if config
.llvm_bolt_profile_generate
&& config
.llvm_bolt_profile_use
.is_some() {
851 "Cannot use both `llvm_bolt_profile_generate` and `llvm_bolt_profile_use` at the same time"
853 crate::detail_exit(1);
856 // Infer the rest of the configuration.
858 // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
859 // running on a completely machine from where it was compiled.
860 let mut cmd
= Command
::new("git");
861 // NOTE: we cannot support running from outside the repository because the only path we have available
862 // is set at compile time, which can be wrong if bootstrap was downloaded from source.
863 // We still support running outside the repository if we find we aren't in a git directory.
864 cmd
.arg("rev-parse").arg("--show-toplevel");
865 // Discard stderr because we expect this to fail when building from a tarball.
867 .stderr(std
::process
::Stdio
::null())
870 .and_then(|output
| if output
.status
.success() { Some(output) }
else { None }
);
871 if let Some(output
) = output
{
872 let git_root
= String
::from_utf8(output
.stdout
).unwrap();
873 // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes.
874 let git_root
= PathBuf
::from(git_root
.trim()).canonicalize().unwrap();
875 let s
= git_root
.to_str().unwrap();
877 // Bootstrap is quite bad at handling /? in front of paths
878 let src
= match s
.strip_prefix("\\\\?\\") {
879 Some(p
) => PathBuf
::from(p
),
880 None
=> PathBuf
::from(git_root
),
882 // If this doesn't have at least `stage0.json`, we guessed wrong. This can happen when,
883 // for example, the build directory is inside of another unrelated git directory.
884 // In that case keep the original `CARGO_MANIFEST_DIR` handling.
886 // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
887 // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
888 if src
.join("src").join("stage0.json").exists() {
892 // We're building from a tarball, not git sources.
893 // We don't support pre-downloaded bootstrap in this case.
897 // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
898 config
.out
= Path
::new(
899 &env
::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
906 let stage0_json
= t
!(std
::fs
::read(&config
.src
.join("src").join("stage0.json")));
908 config
.stage0_metadata
= t
!(serde_json
::from_slice
::<Stage0Metadata
>(&stage0_json
));
911 let get_toml
= |_
| TomlConfig
::default();
913 let get_toml
= |file
: &Path
| {
915 t
!(fs
::read_to_string(file
), format
!("config file {} not found", file
.display()));
916 // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
917 // TomlConfig and sub types to be monomorphized 5x by toml.
918 match toml
::from_str(&contents
)
919 .and_then(|table
: toml
::Value
| TomlConfig
::deserialize(table
))
923 eprintln
!("failed to parse TOML configuration '{}': {}", file
.display(), err
);
924 crate::detail_exit(2);
929 // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
930 let toml_path
= flags
933 .or_else(|| env
::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf
::from
));
934 let using_default_path
= toml_path
.is_none();
935 let mut toml_path
= toml_path
.unwrap_or_else(|| PathBuf
::from("config.toml"));
936 if using_default_path
&& !toml_path
.exists() {
937 toml_path
= config
.src
.join(toml_path
);
940 // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
941 // but not if `config.toml` hasn't been created.
942 let mut toml
= if !using_default_path
|| toml_path
.exists() {
943 config
.config
= Some(toml_path
.clone());
946 config
.config
= None
;
947 TomlConfig
::default()
950 if let Some(include
) = &toml
.profile
{
951 let mut include_path
= config
.src
.clone();
952 include_path
.push("src");
953 include_path
.push("bootstrap");
954 include_path
.push("defaults");
955 include_path
.push(format
!("config.{}.toml", include
));
956 let included_toml
= get_toml(&include_path
);
957 toml
.merge(included_toml
);
960 config
.changelog_seen
= toml
.changelog_seen
;
962 let build
= toml
.build
.unwrap_or_default();
964 set(&mut config
.out
, flags
.build_dir
.or_else(|| build
.build_dir
.map(PathBuf
::from
)));
965 // NOTE: Bootstrap spawns various commands with different working directories.
966 // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
967 if !config
.out
.is_absolute() {
968 // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
969 config
.out
= crate::util
::absolute(&config
.out
);
972 config
.initial_rustc
= build
975 .unwrap_or_else(|| config
.out
.join(config
.build
.triple
).join("stage0/bin/rustc"));
976 config
.initial_cargo
= build
979 .unwrap_or_else(|| config
.out
.join(config
.build
.triple
).join("stage0/bin/cargo"));
981 // NOTE: it's important this comes *after* we set `initial_rustc` just above.
982 if config
.dry_run() {
983 let dir
= config
.out
.join("tmp-dry-run");
984 t
!(fs
::create_dir_all(&dir
));
988 config
.hosts
= if let Some(arg_host
) = flags
.host
{
990 } else if let Some(file_host
) = build
.host
{
991 file_host
.iter().map(|h
| TargetSelection
::from_user(h
)).collect()
995 config
.targets
= if let Some(arg_target
) = flags
.target
{
997 } else if let Some(file_target
) = build
.target
{
998 file_target
.iter().map(|h
| TargetSelection
::from_user(h
)).collect()
1000 // If target is *not* configured, then default to the host
1002 config
.hosts
.clone()
1005 config
.nodejs
= build
.nodejs
.map(PathBuf
::from
);
1006 config
.npm
= build
.npm
.map(PathBuf
::from
);
1007 config
.gdb
= build
.gdb
.map(PathBuf
::from
);
1008 config
.python
= build
.python
.map(PathBuf
::from
);
1009 config
.reuse
= build
.reuse
.map(PathBuf
::from
);
1010 config
.submodules
= build
.submodules
;
1011 set(&mut config
.low_priority
, build
.low_priority
);
1012 set(&mut config
.compiler_docs
, build
.compiler_docs
);
1013 set(&mut config
.docs_minification
, build
.docs_minification
);
1014 set(&mut config
.docs
, build
.docs
);
1015 set(&mut config
.locked_deps
, build
.locked_deps
);
1016 set(&mut config
.vendor
, build
.vendor
);
1017 set(&mut config
.full_bootstrap
, build
.full_bootstrap
);
1018 set(&mut config
.extended
, build
.extended
);
1019 config
.tools
= build
.tools
;
1020 set(&mut config
.verbose
, build
.verbose
);
1021 set(&mut config
.sanitizers
, build
.sanitizers
);
1022 set(&mut config
.profiler
, build
.profiler
);
1023 set(&mut config
.cargo_native_static
, build
.cargo_native_static
);
1024 set(&mut config
.configure_args
, build
.configure_args
);
1025 set(&mut config
.local_rebuild
, build
.local_rebuild
);
1026 set(&mut config
.print_step_timings
, build
.print_step_timings
);
1027 set(&mut config
.print_step_rusage
, build
.print_step_rusage
);
1028 set(&mut config
.patch_binaries_for_nix
, build
.patch_binaries_for_nix
);
1030 config
.verbose
= cmp
::max(config
.verbose
, flags
.verbose
);
1032 if let Some(install
) = toml
.install
{
1033 config
.prefix
= install
.prefix
.map(PathBuf
::from
);
1034 config
.sysconfdir
= install
.sysconfdir
.map(PathBuf
::from
);
1035 config
.datadir
= install
.datadir
.map(PathBuf
::from
);
1036 config
.docdir
= install
.docdir
.map(PathBuf
::from
);
1037 set(&mut config
.bindir
, install
.bindir
.map(PathBuf
::from
));
1038 config
.libdir
= install
.libdir
.map(PathBuf
::from
);
1039 config
.mandir
= install
.mandir
.map(PathBuf
::from
);
1042 // We want the llvm-skip-rebuild flag to take precedence over the
1043 // skip-rebuild config.toml option so we store it separately
1044 // so that we can infer the right value
1045 let mut llvm_skip_rebuild
= flags
.llvm_skip_rebuild
;
1047 // Store off these values as options because if they're not provided
1048 // we'll infer default values for them later
1049 let mut llvm_assertions
= None
;
1050 let mut llvm_tests
= None
;
1051 let mut llvm_plugins
= None
;
1052 let mut debug
= None
;
1053 let mut debug_assertions
= None
;
1054 let mut debug_assertions_std
= None
;
1055 let mut overflow_checks
= None
;
1056 let mut overflow_checks_std
= None
;
1057 let mut debug_logging
= None
;
1058 let mut debuginfo_level
= None
;
1059 let mut debuginfo_level_rustc
= None
;
1060 let mut debuginfo_level_std
= None
;
1061 let mut debuginfo_level_tools
= None
;
1062 let mut debuginfo_level_tests
= None
;
1063 let mut optimize
= None
;
1064 let mut ignore_git
= None
;
1066 if let Some(llvm
) = toml
.llvm
{
1068 Some(StringOrBool
::String(ref s
)) => config
.ccache
= Some(s
.to_string()),
1069 Some(StringOrBool
::Bool(true)) => {
1070 config
.ccache
= Some("ccache".to_string());
1072 Some(StringOrBool
::Bool(false)) | None
=> {}
1074 set(&mut config
.ninja_in_file
, llvm
.ninja
);
1075 llvm_assertions
= llvm
.assertions
;
1076 llvm_tests
= llvm
.tests
;
1077 llvm_plugins
= llvm
.plugins
;
1078 llvm_skip_rebuild
= llvm_skip_rebuild
.or(llvm
.skip_rebuild
);
1079 set(&mut config
.llvm_optimize
, llvm
.optimize
);
1080 set(&mut config
.llvm_thin_lto
, llvm
.thin_lto
);
1081 set(&mut config
.llvm_release_debuginfo
, llvm
.release_debuginfo
);
1082 set(&mut config
.llvm_version_check
, llvm
.version_check
);
1083 set(&mut config
.llvm_static_stdcpp
, llvm
.static_libstdcpp
);
1084 if let Some(v
) = llvm
.link_shared
{
1085 config
.llvm_link_shared
.set(Some(v
));
1087 config
.llvm_targets
= llvm
.targets
.clone();
1088 config
.llvm_experimental_targets
= llvm
.experimental_targets
.clone();
1089 config
.llvm_link_jobs
= llvm
.link_jobs
;
1090 config
.llvm_version_suffix
= llvm
.version_suffix
.clone();
1091 config
.llvm_clang_cl
= llvm
.clang_cl
.clone();
1093 config
.llvm_cflags
= llvm
.cflags
.clone();
1094 config
.llvm_cxxflags
= llvm
.cxxflags
.clone();
1095 config
.llvm_ldflags
= llvm
.ldflags
.clone();
1096 set(&mut config
.llvm_use_libcxx
, llvm
.use_libcxx
);
1097 config
.llvm_use_linker
= llvm
.use_linker
.clone();
1098 config
.llvm_allow_old_toolchain
= llvm
.allow_old_toolchain
.unwrap_or(false);
1099 config
.llvm_polly
= llvm
.polly
.unwrap_or(false);
1100 config
.llvm_clang
= llvm
.clang
.unwrap_or(false);
1101 config
.llvm_build_config
= llvm
.build_config
.clone().unwrap_or(Default
::default());
1102 config
.llvm_from_ci
= match llvm
.download_ci_llvm
{
1103 Some(StringOrBool
::String(s
)) => {
1104 assert
!(s
== "if-available", "unknown option `{}` for download-ci-llvm", s
);
1105 crate::native
::is_ci_llvm_available(&config
, llvm_assertions
.unwrap_or(false))
1107 Some(StringOrBool
::Bool(b
)) => b
,
1111 if config
.llvm_from_ci
{
1112 // None of the LLVM options, except assertions, are supported
1113 // when using downloaded LLVM. We could just ignore these but
1114 // that's potentially confusing, so force them to not be
1115 // explicitly set. The defaults and CI defaults don't
1116 // necessarily match but forcing people to match (somewhat
1117 // arbitrary) CI configuration locally seems bad/hard.
1118 check_ci_llvm
!(llvm
.optimize
);
1119 check_ci_llvm
!(llvm
.thin_lto
);
1120 check_ci_llvm
!(llvm
.release_debuginfo
);
1121 // CI-built LLVM can be either dynamic or static. We won't know until we download it.
1122 check_ci_llvm
!(llvm
.link_shared
);
1123 check_ci_llvm
!(llvm
.static_libstdcpp
);
1124 check_ci_llvm
!(llvm
.targets
);
1125 check_ci_llvm
!(llvm
.experimental_targets
);
1126 check_ci_llvm
!(llvm
.link_jobs
);
1127 check_ci_llvm
!(llvm
.clang_cl
);
1128 check_ci_llvm
!(llvm
.version_suffix
);
1129 check_ci_llvm
!(llvm
.cflags
);
1130 check_ci_llvm
!(llvm
.cxxflags
);
1131 check_ci_llvm
!(llvm
.ldflags
);
1132 check_ci_llvm
!(llvm
.use_libcxx
);
1133 check_ci_llvm
!(llvm
.use_linker
);
1134 check_ci_llvm
!(llvm
.allow_old_toolchain
);
1135 check_ci_llvm
!(llvm
.polly
);
1136 check_ci_llvm
!(llvm
.clang
);
1137 check_ci_llvm
!(llvm
.build_config
);
1138 check_ci_llvm
!(llvm
.plugins
);
1141 // NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above.
1142 if config
.llvm_thin_lto
&& llvm
.link_shared
.is_none() {
1143 // If we're building with ThinLTO on, by default we want to link
1144 // to LLVM shared, to avoid re-doing ThinLTO (which happens in
1145 // the link step) with each stage.
1146 config
.llvm_link_shared
.set(Some(true));
1150 if let Some(rust
) = toml
.rust
{
1152 debug_assertions
= rust
.debug_assertions
;
1153 debug_assertions_std
= rust
.debug_assertions_std
;
1154 overflow_checks
= rust
.overflow_checks
;
1155 overflow_checks_std
= rust
.overflow_checks_std
;
1156 debug_logging
= rust
.debug_logging
;
1157 debuginfo_level
= rust
.debuginfo_level
;
1158 debuginfo_level_rustc
= rust
.debuginfo_level_rustc
;
1159 debuginfo_level_std
= rust
.debuginfo_level_std
;
1160 debuginfo_level_tools
= rust
.debuginfo_level_tools
;
1161 debuginfo_level_tests
= rust
.debuginfo_level_tests
;
1162 config
.rust_split_debuginfo
= rust
1165 .map(SplitDebuginfo
::from_str
)
1166 .map(|v
| v
.expect("invalid value for rust.split_debuginfo"))
1167 .unwrap_or(SplitDebuginfo
::default_for_platform(&config
.build
.triple
));
1168 optimize
= rust
.optimize
;
1169 ignore_git
= rust
.ignore_git
;
1170 config
.rust_new_symbol_mangling
= rust
.new_symbol_mangling
;
1171 set(&mut config
.rust_optimize_tests
, rust
.optimize_tests
);
1172 set(&mut config
.codegen_tests
, rust
.codegen_tests
);
1173 set(&mut config
.rust_rpath
, rust
.rpath
);
1174 set(&mut config
.jemalloc
, rust
.jemalloc
);
1175 set(&mut config
.test_compare_mode
, rust
.test_compare_mode
);
1176 set(&mut config
.backtrace
, rust
.backtrace
);
1177 set(&mut config
.channel
, rust
.channel
);
1178 config
.description
= rust
.description
;
1179 set(&mut config
.rust_dist_src
, rust
.dist_src
);
1180 set(&mut config
.verbose_tests
, rust
.verbose_tests
);
1181 // in the case "false" is set explicitly, do not overwrite the command line args
1182 if let Some(true) = rust
.incremental
{
1183 config
.incremental
= true;
1185 set(&mut config
.use_lld
, rust
.use_lld
);
1186 set(&mut config
.lld_enabled
, rust
.lld
);
1187 set(&mut config
.llvm_tools_enabled
, rust
.llvm_tools
);
1188 config
.rustc_parallel
= rust
.parallel_compiler
.unwrap_or(false);
1189 config
.rustc_default_linker
= rust
.default_linker
;
1190 config
.musl_root
= rust
.musl_root
.map(PathBuf
::from
);
1191 config
.save_toolstates
= rust
.save_toolstates
.map(PathBuf
::from
);
1192 set(&mut config
.deny_warnings
, flags
.deny_warnings
.or(rust
.deny_warnings
));
1193 set(&mut config
.backtrace_on_ice
, rust
.backtrace_on_ice
);
1194 set(&mut config
.rust_verify_llvm_ir
, rust
.verify_llvm_ir
);
1195 config
.rust_thin_lto_import_instr_limit
= rust
.thin_lto_import_instr_limit
;
1196 set(&mut config
.rust_remap_debuginfo
, rust
.remap_debuginfo
);
1197 set(&mut config
.control_flow_guard
, rust
.control_flow_guard
);
1198 config
.llvm_libunwind_default
= rust
1200 .map(|v
| v
.parse().expect("failed to parse rust.llvm-libunwind"));
1202 if let Some(ref backends
) = rust
.codegen_backends
{
1203 config
.rust_codegen_backends
=
1204 backends
.iter().map(|s
| INTERNER
.intern_str(s
)).collect();
1207 config
.rust_codegen_units
= rust
.codegen_units
.map(threads_from_config
);
1208 config
.rust_codegen_units_std
= rust
.codegen_units_std
.map(threads_from_config
);
1209 config
.rust_profile_use
= flags
.rust_profile_use
.or(rust
.profile_use
);
1210 config
.rust_profile_generate
= flags
.rust_profile_generate
.or(rust
.profile_generate
);
1211 config
.download_rustc_commit
= config
.download_ci_rustc_commit(rust
.download_rustc
);
1213 config
.rust_lto
= rust
1216 .map(|value
| RustcLto
::from_str(value
).unwrap())
1217 .unwrap_or_default();
1219 config
.rust_profile_use
= flags
.rust_profile_use
;
1220 config
.rust_profile_generate
= flags
.rust_profile_generate
;
1223 if let Some(t
) = toml
.target
{
1224 for (triple
, cfg
) in t
{
1225 let mut target
= Target
::from_triple(&triple
);
1227 if let Some(ref s
) = cfg
.llvm_config
{
1228 target
.llvm_config
= Some(config
.src
.join(s
));
1230 target
.llvm_has_rust_patches
= cfg
.llvm_has_rust_patches
;
1231 if let Some(ref s
) = cfg
.llvm_filecheck
{
1232 target
.llvm_filecheck
= Some(config
.src
.join(s
));
1234 target
.llvm_libunwind
= cfg
1237 .map(|v
| v
.parse().expect("failed to parse rust.llvm-libunwind"));
1238 if let Some(ref s
) = cfg
.android_ndk
{
1239 target
.ndk
= Some(config
.src
.join(s
));
1241 if let Some(s
) = cfg
.no_std
{
1244 target
.cc
= cfg
.cc
.map(PathBuf
::from
).or_else(|| {
1245 target
.ndk
.as_ref().map(|ndk
| ndk_compiler(Language
::C
, &triple
, ndk
))
1247 target
.cxx
= cfg
.cxx
.map(PathBuf
::from
).or_else(|| {
1248 target
.ndk
.as_ref().map(|ndk
| ndk_compiler(Language
::CPlusPlus
, &triple
, ndk
))
1250 target
.ar
= cfg
.ar
.map(PathBuf
::from
);
1251 target
.ranlib
= cfg
.ranlib
.map(PathBuf
::from
);
1252 target
.linker
= cfg
.linker
.map(PathBuf
::from
);
1253 target
.crt_static
= cfg
.crt_static
;
1254 target
.musl_root
= cfg
.musl_root
.map(PathBuf
::from
);
1255 target
.musl_libdir
= cfg
.musl_libdir
.map(PathBuf
::from
);
1256 target
.wasi_root
= cfg
.wasi_root
.map(PathBuf
::from
);
1257 target
.qemu_rootfs
= cfg
.qemu_rootfs
.map(PathBuf
::from
);
1258 target
.sanitizers
= cfg
.sanitizers
;
1259 target
.profiler
= cfg
.profiler
;
1261 config
.target_config
.insert(TargetSelection
::from_user(&triple
), target
);
1265 if config
.llvm_from_ci
{
1266 let triple
= &config
.build
.triple
;
1267 let ci_llvm_bin
= config
.ci_llvm_root().join("bin");
1268 let mut build_target
= config
1270 .entry(config
.build
)
1271 .or_insert_with(|| Target
::from_triple(&triple
));
1273 check_ci_llvm
!(build_target
.llvm_config
);
1274 check_ci_llvm
!(build_target
.llvm_filecheck
);
1275 build_target
.llvm_config
= Some(ci_llvm_bin
.join(exe("llvm-config", config
.build
)));
1276 build_target
.llvm_filecheck
= Some(ci_llvm_bin
.join(exe("FileCheck", config
.build
)));
1279 if let Some(t
) = toml
.dist
{
1280 config
.dist_sign_folder
= t
.sign_folder
.map(PathBuf
::from
);
1281 config
.dist_upload_addr
= t
.upload_addr
;
1282 config
.dist_compression_formats
= t
.compression_formats
;
1283 set(&mut config
.rust_dist_src
, t
.src_tarball
);
1284 set(&mut config
.missing_tools
, t
.missing_tools
);
1287 if let Some(r
) = build
.rustfmt
{
1288 *config
.initial_rustfmt
.borrow_mut() = if r
.exists() {
1289 RustfmtState
::SystemToolchain(r
)
1291 RustfmtState
::Unavailable
1294 // If using a system toolchain for bootstrapping, see if that has rustfmt available.
1295 let host
= config
.build
;
1296 let rustfmt_path
= config
.initial_rustc
.with_file_name(exe("rustfmt", host
));
1297 let bin_root
= config
.out
.join(host
.triple
).join("stage0");
1298 if !rustfmt_path
.starts_with(&bin_root
) {
1299 // Using a system-provided toolchain; we shouldn't download rustfmt.
1300 *config
.initial_rustfmt
.borrow_mut() = RustfmtState
::SystemToolchain(rustfmt_path
);
1304 // Now that we've reached the end of our configuration, infer the
1305 // default values for all options that we haven't otherwise stored yet.
1307 config
.llvm_skip_rebuild
= llvm_skip_rebuild
.unwrap_or(false);
1308 config
.llvm_assertions
= llvm_assertions
.unwrap_or(false);
1309 config
.llvm_tests
= llvm_tests
.unwrap_or(false);
1310 config
.llvm_plugins
= llvm_plugins
.unwrap_or(false);
1311 config
.rust_optimize
= optimize
.unwrap_or(true);
1313 let default = debug
== Some(true);
1314 config
.rust_debug_assertions
= debug_assertions
.unwrap_or(default);
1315 config
.rust_debug_assertions_std
=
1316 debug_assertions_std
.unwrap_or(config
.rust_debug_assertions
);
1317 config
.rust_overflow_checks
= overflow_checks
.unwrap_or(default);
1318 config
.rust_overflow_checks_std
=
1319 overflow_checks_std
.unwrap_or(config
.rust_overflow_checks
);
1321 config
.rust_debug_logging
= debug_logging
.unwrap_or(config
.rust_debug_assertions
);
1323 let with_defaults
= |debuginfo_level_specific
: Option
<u32>| {
1324 debuginfo_level_specific
.or(debuginfo_level
).unwrap_or(if debug
== Some(true) {
1330 config
.rust_debuginfo_level_rustc
= with_defaults(debuginfo_level_rustc
);
1331 config
.rust_debuginfo_level_std
= with_defaults(debuginfo_level_std
);
1332 config
.rust_debuginfo_level_tools
= with_defaults(debuginfo_level_tools
);
1333 config
.rust_debuginfo_level_tests
= debuginfo_level_tests
.unwrap_or(0);
1335 let default = config
.channel
== "dev";
1336 config
.ignore_git
= ignore_git
.unwrap_or(default);
1337 config
.rust_info
= GitInfo
::new(config
.ignore_git
, &config
.src
);
1339 let download_rustc
= config
.download_rustc_commit
.is_some();
1340 // See https://github.com/rust-lang/compiler-team/issues/326
1341 config
.stage
= match config
.cmd
{
1342 Subcommand
::Check { .. }
=> flags
.stage
.or(build
.check_stage
).unwrap_or(0),
1343 // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden.
1344 Subcommand
::Doc { .. }
=> {
1345 flags
.stage
.or(build
.doc_stage
).unwrap_or(if download_rustc { 2 }
else { 0 }
)
1347 Subcommand
::Build { .. }
=> {
1348 flags
.stage
.or(build
.build_stage
).unwrap_or(if download_rustc { 2 }
else { 1 }
)
1350 Subcommand
::Test { .. }
=> {
1351 flags
.stage
.or(build
.test_stage
).unwrap_or(if download_rustc { 2 }
else { 1 }
)
1353 Subcommand
::Bench { .. }
=> flags
.stage
.or(build
.bench_stage
).unwrap_or(2),
1354 Subcommand
::Dist { .. }
=> flags
.stage
.or(build
.dist_stage
).unwrap_or(2),
1355 Subcommand
::Install { .. }
=> flags
.stage
.or(build
.install_stage
).unwrap_or(2),
1356 // These are all bootstrap tools, which don't depend on the compiler.
1357 // The stage we pass shouldn't matter, but use 0 just in case.
1358 Subcommand
::Clean { .. }
1359 | Subcommand
::Clippy { .. }
1360 | Subcommand
::Fix { .. }
1361 | Subcommand
::Run { .. }
1362 | Subcommand
::Setup { .. }
1363 | Subcommand
::Format { .. }
=> flags
.stage
.unwrap_or(0),
1366 // CI should always run stage 2 builds, unless it specifically states otherwise
1368 if flags
.stage
.is_none() && crate::CiEnv
::current() != crate::CiEnv
::None
{
1370 Subcommand
::Test { .. }
1371 | Subcommand
::Doc { .. }
1372 | Subcommand
::Build { .. }
1373 | Subcommand
::Bench { .. }
1374 | Subcommand
::Dist { .. }
1375 | Subcommand
::Install { .. }
=> {
1378 "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`",
1382 Subcommand
::Clean { .. }
1383 | Subcommand
::Check { .. }
1384 | Subcommand
::Clippy { .. }
1385 | Subcommand
::Fix { .. }
1386 | Subcommand
::Run { .. }
1387 | Subcommand
::Setup { .. }
1388 | Subcommand
::Format { .. }
=> {}
1395 pub(crate) fn dry_run(&self) -> bool
{
1396 match self.dry_run
{
1397 DryRun
::Disabled
=> false,
1398 DryRun
::SelfCheck
| DryRun
::UserSelected
=> true,
1402 /// A git invocation which runs inside the source directory.
1404 /// Use this rather than `Command::new("git")` in order to support out-of-tree builds.
1405 pub(crate) fn git(&self) -> Command
{
1406 let mut git
= Command
::new("git");
1407 git
.current_dir(&self.src
);
1411 /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
1412 /// Return the version it would have used for the given commit.
1413 pub(crate) fn artifact_version_part(&self, commit
: &str) -> String
{
1414 let (channel
, version
) = if self.rust_info
.is_managed_git_subrepository() {
1415 let mut channel
= self.git();
1416 channel
.arg("show").arg(format
!("{}:src/ci/channel", commit
));
1417 let channel
= output(&mut channel
);
1418 let mut version
= self.git();
1419 version
.arg("show").arg(format
!("{}:src/version", commit
));
1420 let version
= output(&mut version
);
1421 (channel
.trim().to_owned(), version
.trim().to_owned())
1423 let channel
= fs
::read_to_string(self.src
.join("src/ci/channel"));
1424 let version
= fs
::read_to_string(self.src
.join("src/version"));
1425 match (channel
, version
) {
1426 (Ok(channel
), Ok(version
)) => {
1427 (channel
.trim().to_owned(), version
.trim().to_owned())
1429 (channel
, version
) => {
1430 let src
= self.src
.display();
1431 eprintln
!("error: failed to determine artifact channel and/or version");
1433 "help: consider using a git checkout or ensure these files are readable"
1435 if let Err(channel
) = channel
{
1436 eprintln
!("reading {}/src/ci/channel failed: {:?}", src
, channel
);
1438 if let Err(version
) = version
{
1439 eprintln
!("reading {}/src/version failed: {:?}", src
, version
);
1446 match channel
.as_str() {
1447 "stable" => version
,
1449 "nightly" => channel
,
1450 other
=> unreachable
!("{:?} is not recognized as a valid channel", other
),
1454 /// Try to find the relative path of `bindir`, otherwise return it in full.
1455 pub fn bindir_relative(&self) -> &Path
{
1456 let bindir
= &self.bindir
;
1457 if bindir
.is_absolute() {
1458 // Try to make it relative to the prefix.
1459 if let Some(prefix
) = &self.prefix
{
1460 if let Ok(stripped
) = bindir
.strip_prefix(prefix
) {
1468 /// Try to find the relative path of `libdir`.
1469 pub fn libdir_relative(&self) -> Option
<&Path
> {
1470 let libdir
= self.libdir
.as_ref()?
;
1471 if libdir
.is_relative() {
1474 // Try to make it relative to the prefix.
1475 libdir
.strip_prefix(self.prefix
.as_ref()?
).ok()
1479 /// The absolute path to the downloaded LLVM artifacts.
1480 pub(crate) fn ci_llvm_root(&self) -> PathBuf
{
1481 assert
!(self.llvm_from_ci
);
1482 self.out
.join(&*self.build
.triple
).join("ci-llvm")
1485 /// Determine whether llvm should be linked dynamically.
1487 /// If `false`, llvm should be linked statically.
1488 /// This is computed on demand since LLVM might have to first be downloaded from CI.
1489 pub(crate) fn llvm_link_shared(&self) -> bool
{
1490 let mut opt
= self.llvm_link_shared
.get();
1491 if opt
.is_none() && self.dry_run() {
1492 // just assume static for now - dynamic linking isn't supported on all platforms
1496 let llvm_link_shared
= *opt
.get_or_insert_with(|| {
1497 if self.llvm_from_ci
{
1498 self.maybe_download_ci_llvm();
1499 let ci_llvm
= self.ci_llvm_root();
1501 std
::fs
::read_to_string(ci_llvm
.join("link-type.txt")),
1502 format
!("CI llvm missing: {}", ci_llvm
.display())
1504 link_type
== "dynamic"
1506 // unclear how thought-through this default is, but it maintains compatibility with
1507 // previous behavior
1511 self.llvm_link_shared
.set(opt
);
1515 /// Return whether we will use a downloaded, pre-compiled version of rustc, or just build from source.
1516 pub(crate) fn download_rustc(&self) -> bool
{
1517 self.download_rustc_commit().is_some()
1520 pub(crate) fn download_rustc_commit(&self) -> Option
<&'
static str> {
1521 static DOWNLOAD_RUSTC
: OnceCell
<Option
<String
>> = OnceCell
::new();
1522 if self.dry_run() && DOWNLOAD_RUSTC
.get().is_none() {
1523 // avoid trying to actually download the commit
1528 .get_or_init(|| match &self.download_rustc_commit
{
1531 self.download_ci_rustc(commit
);
1532 Some(commit
.clone())
1538 pub(crate) fn initial_rustfmt(&self) -> Option
<PathBuf
> {
1539 match &mut *self.initial_rustfmt
.borrow_mut() {
1540 RustfmtState
::SystemToolchain(p
) | RustfmtState
::Downloaded(p
) => Some(p
.clone()),
1541 RustfmtState
::Unavailable
=> None
,
1542 r @ RustfmtState
::LazyEvaluated
=> {
1544 return Some(PathBuf
::new());
1546 let path
= self.maybe_download_rustfmt();
1547 *r
= if let Some(p
) = &path
{
1548 RustfmtState
::Downloaded(p
.clone())
1550 RustfmtState
::Unavailable
1557 pub fn verbose(&self, msg
: &str) {
1558 if self.verbose
> 0 {
1559 println
!("{}", msg
);
1563 pub fn sanitizers_enabled(&self, target
: TargetSelection
) -> bool
{
1564 self.target_config
.get(&target
).map(|t
| t
.sanitizers
).flatten().unwrap_or(self.sanitizers
)
1567 pub fn any_sanitizers_enabled(&self) -> bool
{
1568 self.target_config
.values().any(|t
| t
.sanitizers
== Some(true)) || self.sanitizers
1571 pub fn profiler_enabled(&self, target
: TargetSelection
) -> bool
{
1572 self.target_config
.get(&target
).map(|t
| t
.profiler
).flatten().unwrap_or(self.profiler
)
1575 pub fn any_profiler_enabled(&self) -> bool
{
1576 self.target_config
.values().any(|t
| t
.profiler
== Some(true)) || self.profiler
1579 pub fn llvm_enabled(&self) -> bool
{
1580 self.rust_codegen_backends
.contains(&INTERNER
.intern_str("llvm"))
1583 pub fn llvm_libunwind(&self, target
: TargetSelection
) -> LlvmLibunwind
{
1586 .and_then(|t
| t
.llvm_libunwind
)
1587 .or(self.llvm_libunwind_default
)
1588 .unwrap_or(if target
.contains("fuchsia") {
1589 LlvmLibunwind
::InTree
1595 pub fn submodules(&self, rust_info
: &GitInfo
) -> bool
{
1596 self.submodules
.unwrap_or(rust_info
.is_managed_git_subrepository())
1599 /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
1600 fn download_ci_rustc_commit(&self, download_rustc
: Option
<StringOrBool
>) -> Option
<String
> {
1601 // If `download-rustc` is not set, default to rebuilding.
1602 let if_unchanged
= match download_rustc
{
1603 None
| Some(StringOrBool
::Bool(false)) => return None
,
1604 Some(StringOrBool
::Bool(true)) => false,
1605 Some(StringOrBool
::String(s
)) if s
== "if-unchanged" => true,
1606 Some(StringOrBool
::String(other
)) => {
1607 panic
!("unrecognized option for download-rustc: {}", other
)
1611 // Handle running from a directory other than the top level
1612 let top_level
= output(self.git().args(&["rev-parse", "--show-toplevel"]));
1613 let top_level
= top_level
.trim_end();
1614 let compiler
= format
!("{top_level}/compiler/");
1615 let library
= format
!("{top_level}/library/");
1617 // Look for a version to compare to based on the current commit.
1618 // Only commits merged by bors will have CI artifacts.
1619 let merge_base
= output(
1622 .arg(format
!("--author={}", self.stage0_metadata
.config
.git_merge_commit_email
))
1623 .args(&["-n1", "--first-parent", "HEAD"]),
1625 let commit
= merge_base
.trim_end();
1626 if commit
.is_empty() {
1627 println
!("error: could not find commit hash for downloading rustc");
1628 println
!("help: maybe your repository history is too shallow?");
1629 println
!("help: consider disabling `download-rustc`");
1630 println
!("help: or fetch enough history to include one upstream commit");
1631 crate::detail_exit(1);
1634 // Warn if there were changes to the compiler or standard library since the ancestor commit.
1635 let has_changes
= !t
!(self
1637 .args(&["diff-index", "--quiet", &commit
, "--", &compiler
, &library
])
1642 if self.verbose
> 0 {
1644 "warning: saw changes to compiler/ or library/ since {commit}; \
1645 ignoring `download-rustc`"
1651 "warning: `download-rustc` is enabled, but there are changes to \
1652 compiler/ or library/"
1656 Some(commit
.to_string())
1660 fn set
<T
>(field
: &mut T
, val
: Option
<T
>) {
1661 if let Some(v
) = val
{
1666 fn threads_from_config(v
: u32) -> u32 {
1668 0 => std
::thread
::available_parallelism().map_or(1, std
::num
::NonZeroUsize
::get
) as u32,