1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Serialized configuration of a build.
13 //! This module implements parsing `config.toml` configuration files to tweak
14 //! how the build runs.
16 use std
::collections
::{HashMap, HashSet}
;
18 use std
::fs
::{self, File}
;
19 use std
::io
::prelude
::*;
20 use std
::path
::{Path, PathBuf}
;
27 use cache
::{INTERNER, Interned}
;
29 pub use flags
::Subcommand
;
31 /// Global configuration for the entire build and/or bootstrap.
33 /// This structure is derived from a combination of both `config.toml` and
34 /// `config.mk`. As of the time of this writing it's unlikely that `config.toml`
35 /// is used all that much, so this is primarily filled out by `config.mk` which
36 /// is generated from `./configure`.
38 /// Note that this structure is not decoded directly into, but rather it is
39 /// filled out from the decoded forms of the structs below. For documentation
40 /// each field, see the corresponding fields in
41 /// `config.toml.example`.
44 pub ccache
: Option
<String
>,
48 pub fast_submodules
: bool
,
49 pub compiler_docs
: bool
,
51 pub locked_deps
: bool
,
53 pub target_config
: HashMap
<Interned
<String
>, Target
>,
54 pub full_bootstrap
: bool
,
56 pub tools
: Option
<HashSet
<String
>>,
60 pub exclude
: Vec
<PathBuf
>,
61 pub rustc_error_format
: Option
<String
>,
63 pub run_host_only
: bool
,
65 pub on_fail
: Option
<String
>,
66 pub stage
: Option
<u32>,
67 pub keep_stage
: Option
<u32>,
69 pub jobs
: Option
<u32>,
71 pub incremental
: bool
,
74 pub deny_warnings
: bool
,
75 pub backtrace_on_ice
: bool
,
77 // llvm codegen options
78 pub llvm_enabled
: bool
,
79 pub llvm_assertions
: bool
,
80 pub llvm_optimize
: bool
,
81 pub llvm_release_debuginfo
: bool
,
82 pub llvm_version_check
: bool
,
83 pub llvm_static_stdcpp
: bool
,
84 pub llvm_link_shared
: bool
,
85 pub llvm_targets
: Option
<String
>,
86 pub llvm_experimental_targets
: String
,
87 pub llvm_link_jobs
: Option
<u32>,
89 pub lld_enabled
: bool
,
91 // rust codegen options
92 pub rust_optimize
: bool
,
93 pub rust_codegen_units
: Option
<u32>,
94 pub rust_debug_assertions
: bool
,
95 pub rust_debuginfo
: bool
,
96 pub rust_debuginfo_lines
: bool
,
97 pub rust_debuginfo_only_std
: bool
,
98 pub rust_debuginfo_tools
: bool
,
100 pub rustc_parallel_queries
: bool
,
101 pub rustc_default_linker
: Option
<String
>,
102 pub rust_optimize_tests
: bool
,
103 pub rust_debuginfo_tests
: bool
,
104 pub rust_dist_src
: bool
,
105 pub rust_codegen_backends
: Vec
<Interned
<String
>>,
106 pub rust_codegen_backends_dir
: String
,
108 pub build
: Interned
<String
>,
109 pub hosts
: Vec
<Interned
<String
>>,
110 pub targets
: Vec
<Interned
<String
>>,
111 pub local_rebuild
: bool
,
114 pub dist_sign_folder
: Option
<PathBuf
>,
115 pub dist_upload_addr
: Option
<String
>,
116 pub dist_gpg_password_file
: Option
<PathBuf
>,
119 pub debug_jemalloc
: bool
,
120 pub use_jemalloc
: bool
,
121 pub backtrace
: bool
, // support for RUST_BACKTRACE
122 pub wasm_syscall
: bool
,
125 pub low_priority
: bool
,
127 pub quiet_tests
: bool
,
129 pub save_toolstates
: Option
<PathBuf
>,
130 pub print_step_timings
: bool
,
132 // Fallback musl-root for all targets
133 pub musl_root
: Option
<PathBuf
>,
134 pub prefix
: Option
<PathBuf
>,
135 pub sysconfdir
: Option
<PathBuf
>,
136 pub datadir
: Option
<PathBuf
>,
137 pub docdir
: Option
<PathBuf
>,
138 pub bindir
: Option
<PathBuf
>,
139 pub libdir
: Option
<PathBuf
>,
140 pub mandir
: Option
<PathBuf
>,
141 pub codegen_tests
: bool
,
142 pub nodejs
: Option
<PathBuf
>,
143 pub gdb
: Option
<PathBuf
>,
144 pub python
: Option
<PathBuf
>,
145 pub openssl_static
: bool
,
146 pub configure_args
: Vec
<String
>,
148 // These are either the stage0 downloaded binaries or the locally installed ones.
149 pub initial_cargo
: PathBuf
,
150 pub initial_rustc
: PathBuf
,
154 /// Per-target configuration stored in the global configuration structure.
157 /// Some(path to llvm-config) if using an external LLVM.
158 pub llvm_config
: Option
<PathBuf
>,
159 pub jemalloc
: Option
<PathBuf
>,
160 pub cc
: Option
<PathBuf
>,
161 pub cxx
: Option
<PathBuf
>,
162 pub ar
: Option
<PathBuf
>,
163 pub linker
: Option
<PathBuf
>,
164 pub ndk
: Option
<PathBuf
>,
165 pub crt_static
: Option
<bool
>,
166 pub musl_root
: Option
<PathBuf
>,
167 pub qemu_rootfs
: Option
<PathBuf
>,
171 /// Structure of the `config.toml` file that configuration is read from.
173 /// This structure uses `Decodable` to automatically decode a TOML configuration
174 /// file into this format, and then this is traversed and written into the above
175 /// `Config` structure.
176 #[derive(Deserialize, Default)]
177 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
179 build
: Option
<Build
>,
180 install
: Option
<Install
>,
183 target
: Option
<HashMap
<String
, TomlTarget
>>,
187 /// TOML representation of various global build decisions.
188 #[derive(Deserialize, Default, Clone)]
189 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
191 build
: Option
<String
>,
196 cargo
: Option
<String
>,
197 rustc
: Option
<String
>,
198 low_priority
: Option
<bool
>,
199 compiler_docs
: Option
<bool
>,
201 submodules
: Option
<bool
>,
202 fast_submodules
: Option
<bool
>,
204 locked_deps
: Option
<bool
>,
205 vendor
: Option
<bool
>,
206 nodejs
: Option
<String
>,
207 python
: Option
<String
>,
208 full_bootstrap
: Option
<bool
>,
209 extended
: Option
<bool
>,
210 tools
: Option
<HashSet
<String
>>,
211 verbose
: Option
<usize>,
212 sanitizers
: Option
<bool
>,
213 profiler
: Option
<bool
>,
214 openssl_static
: Option
<bool
>,
215 configure_args
: Option
<Vec
<String
>>,
216 local_rebuild
: Option
<bool
>,
217 print_step_timings
: Option
<bool
>,
220 /// TOML representation of various global install decisions.
221 #[derive(Deserialize, Default, Clone)]
222 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
224 prefix
: Option
<String
>,
225 sysconfdir
: Option
<String
>,
226 datadir
: Option
<String
>,
227 docdir
: Option
<String
>,
228 bindir
: Option
<String
>,
229 libdir
: Option
<String
>,
230 mandir
: Option
<String
>,
232 // standard paths, currently unused
233 infodir
: Option
<String
>,
234 localstatedir
: Option
<String
>,
237 /// TOML representation of how the LLVM build is configured.
238 #[derive(Deserialize, Default)]
239 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
241 enabled
: Option
<bool
>,
242 ccache
: Option
<StringOrBool
>,
244 assertions
: Option
<bool
>,
245 optimize
: Option
<bool
>,
246 release_debuginfo
: Option
<bool
>,
247 version_check
: Option
<bool
>,
248 static_libstdcpp
: Option
<bool
>,
249 targets
: Option
<String
>,
250 experimental_targets
: Option
<String
>,
251 link_jobs
: Option
<u32>,
252 link_shared
: Option
<bool
>,
255 #[derive(Deserialize, Default, Clone)]
256 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
258 sign_folder
: Option
<String
>,
259 gpg_password_file
: Option
<String
>,
260 upload_addr
: Option
<String
>,
261 src_tarball
: Option
<bool
>,
264 #[derive(Deserialize)]
271 impl Default
for StringOrBool
{
272 fn default() -> StringOrBool
{
273 StringOrBool
::Bool(false)
277 /// TOML representation of how the Rust build is configured.
278 #[derive(Deserialize, Default)]
279 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
281 optimize
: Option
<bool
>,
282 codegen_units
: Option
<u32>,
283 debug_assertions
: Option
<bool
>,
284 debuginfo
: Option
<bool
>,
285 debuginfo_lines
: Option
<bool
>,
286 debuginfo_only_std
: Option
<bool
>,
287 debuginfo_tools
: Option
<bool
>,
288 experimental_parallel_queries
: Option
<bool
>,
289 debug_jemalloc
: Option
<bool
>,
290 use_jemalloc
: Option
<bool
>,
291 backtrace
: Option
<bool
>,
292 default_linker
: Option
<String
>,
293 channel
: Option
<String
>,
294 musl_root
: Option
<String
>,
296 optimize_tests
: Option
<bool
>,
297 debuginfo_tests
: Option
<bool
>,
298 codegen_tests
: Option
<bool
>,
299 ignore_git
: Option
<bool
>,
301 dist_src
: Option
<bool
>,
302 quiet_tests
: Option
<bool
>,
303 test_miri
: Option
<bool
>,
304 save_toolstates
: Option
<String
>,
305 codegen_backends
: Option
<Vec
<String
>>,
306 codegen_backends_dir
: Option
<String
>,
307 wasm_syscall
: Option
<bool
>,
309 deny_warnings
: Option
<bool
>,
310 backtrace_on_ice
: Option
<bool
>,
313 /// TOML representation of how each build target is configured.
314 #[derive(Deserialize, Default)]
315 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
317 llvm_config
: Option
<String
>,
318 jemalloc
: Option
<String
>,
322 linker
: Option
<String
>,
323 android_ndk
: Option
<String
>,
324 crt_static
: Option
<bool
>,
325 musl_root
: Option
<String
>,
326 qemu_rootfs
: Option
<String
>,
330 fn path_from_python(var_key
: &str) -> PathBuf
{
331 match env
::var_os(var_key
) {
332 // Do not trust paths from Python and normalize them slightly (#49785).
333 Some(var_val
) => Path
::new(&var_val
).components().collect(),
334 _
=> panic
!("expected '{}' to be set", var_key
),
338 pub fn default_opts() -> Config
{
339 let mut config
= Config
::default();
340 config
.llvm_enabled
= true;
341 config
.llvm_optimize
= true;
342 config
.llvm_version_check
= true;
343 config
.use_jemalloc
= true;
344 config
.backtrace
= true;
345 config
.rust_optimize
= true;
346 config
.rust_optimize_tests
= true;
347 config
.submodules
= true;
348 config
.fast_submodules
= true;
350 config
.rust_rpath
= true;
351 config
.channel
= "dev".to_string();
352 config
.codegen_tests
= true;
353 config
.ignore_git
= false;
354 config
.rust_dist_src
= true;
355 config
.test_miri
= false;
356 config
.rust_codegen_backends
= vec
![INTERNER
.intern_str("llvm")];
357 config
.rust_codegen_backends_dir
= "codegen-backends".to_owned();
358 config
.deny_warnings
= true;
360 // set by bootstrap.py
361 config
.build
= INTERNER
.intern_str(&env
::var("BUILD").expect("'BUILD' to be set"));
362 config
.src
= Config
::path_from_python("SRC");
363 config
.out
= Config
::path_from_python("BUILD_DIR");
365 let stage0_root
= config
.out
.join(&config
.build
).join("stage0/bin");
366 config
.initial_rustc
= stage0_root
.join(exe("rustc", &config
.build
));
367 config
.initial_cargo
= stage0_root
.join(exe("cargo", &config
.build
));
372 pub fn parse(args
: &[String
]) -> Config
{
373 let flags
= Flags
::parse(&args
);
374 let file
= flags
.config
.clone();
375 let mut config
= Config
::default_opts();
376 config
.exclude
= flags
.exclude
;
377 config
.rustc_error_format
= flags
.rustc_error_format
;
378 config
.on_fail
= flags
.on_fail
;
379 config
.stage
= flags
.stage
;
380 config
.jobs
= flags
.jobs
;
381 config
.cmd
= flags
.cmd
;
382 config
.incremental
= flags
.incremental
;
383 config
.dry_run
= flags
.dry_run
;
384 config
.keep_stage
= flags
.keep_stage
;
385 if let Some(value
) = flags
.warnings
{
386 config
.deny_warnings
= value
;
390 let dir
= config
.out
.join("tmp-dry-run");
391 t
!(fs
::create_dir_all(&dir
));
395 // If --target was specified but --host wasn't specified, don't run any host-only tests.
396 config
.run_host_only
= !(flags
.host
.is_empty() && !flags
.target
.is_empty());
398 let toml
= file
.map(|file
| {
399 let mut f
= t
!(File
::open(&file
));
400 let mut contents
= String
::new();
401 t
!(f
.read_to_string(&mut contents
));
402 match toml
::from_str(&contents
) {
405 println
!("failed to parse TOML configuration '{}': {}",
406 file
.display(), err
);
410 }).unwrap_or_else(|| TomlConfig
::default());
412 let build
= toml
.build
.clone().unwrap_or(Build
::default());
413 // set by bootstrap.py
414 config
.hosts
.push(config
.build
.clone());
415 for host
in build
.host
.iter() {
416 let host
= INTERNER
.intern_str(host
);
417 if !config
.hosts
.contains(&host
) {
418 config
.hosts
.push(host
);
421 for target
in config
.hosts
.iter().cloned()
422 .chain(build
.target
.iter().map(|s
| INTERNER
.intern_str(s
)))
424 if !config
.targets
.contains(&target
) {
425 config
.targets
.push(target
);
428 config
.hosts
= if !flags
.host
.is_empty() {
433 config
.targets
= if !flags
.target
.is_empty() {
440 config
.nodejs
= build
.nodejs
.map(PathBuf
::from
);
441 config
.gdb
= build
.gdb
.map(PathBuf
::from
);
442 config
.python
= build
.python
.map(PathBuf
::from
);
443 set(&mut config
.low_priority
, build
.low_priority
);
444 set(&mut config
.compiler_docs
, build
.compiler_docs
);
445 set(&mut config
.docs
, build
.docs
);
446 set(&mut config
.submodules
, build
.submodules
);
447 set(&mut config
.fast_submodules
, build
.fast_submodules
);
448 set(&mut config
.locked_deps
, build
.locked_deps
);
449 set(&mut config
.vendor
, build
.vendor
);
450 set(&mut config
.full_bootstrap
, build
.full_bootstrap
);
451 set(&mut config
.extended
, build
.extended
);
452 config
.tools
= build
.tools
;
453 set(&mut config
.verbose
, build
.verbose
);
454 set(&mut config
.sanitizers
, build
.sanitizers
);
455 set(&mut config
.profiler
, build
.profiler
);
456 set(&mut config
.openssl_static
, build
.openssl_static
);
457 set(&mut config
.configure_args
, build
.configure_args
);
458 set(&mut config
.local_rebuild
, build
.local_rebuild
);
459 set(&mut config
.print_step_timings
, build
.print_step_timings
);
460 config
.verbose
= cmp
::max(config
.verbose
, flags
.verbose
);
462 if let Some(ref install
) = toml
.install
{
463 config
.prefix
= install
.prefix
.clone().map(PathBuf
::from
);
464 config
.sysconfdir
= install
.sysconfdir
.clone().map(PathBuf
::from
);
465 config
.datadir
= install
.datadir
.clone().map(PathBuf
::from
);
466 config
.docdir
= install
.docdir
.clone().map(PathBuf
::from
);
467 config
.bindir
= install
.bindir
.clone().map(PathBuf
::from
);
468 config
.libdir
= install
.libdir
.clone().map(PathBuf
::from
);
469 config
.mandir
= install
.mandir
.clone().map(PathBuf
::from
);
472 // Store off these values as options because if they're not provided
473 // we'll infer default values for them later
474 let mut llvm_assertions
= None
;
475 let mut debuginfo_lines
= None
;
476 let mut debuginfo_only_std
= None
;
477 let mut debuginfo_tools
= None
;
478 let mut debug
= None
;
479 let mut debug_jemalloc
= None
;
480 let mut debuginfo
= None
;
481 let mut debug_assertions
= None
;
482 let mut optimize
= None
;
483 let mut ignore_git
= None
;
485 if let Some(ref llvm
) = toml
.llvm
{
487 Some(StringOrBool
::String(ref s
)) => {
488 config
.ccache
= Some(s
.to_string())
490 Some(StringOrBool
::Bool(true)) => {
491 config
.ccache
= Some("ccache".to_string());
493 Some(StringOrBool
::Bool(false)) | None
=> {}
495 set(&mut config
.ninja
, llvm
.ninja
);
496 set(&mut config
.llvm_enabled
, llvm
.enabled
);
497 llvm_assertions
= llvm
.assertions
;
498 set(&mut config
.llvm_optimize
, llvm
.optimize
);
499 set(&mut config
.llvm_release_debuginfo
, llvm
.release_debuginfo
);
500 set(&mut config
.llvm_version_check
, llvm
.version_check
);
501 set(&mut config
.llvm_static_stdcpp
, llvm
.static_libstdcpp
);
502 set(&mut config
.llvm_link_shared
, llvm
.link_shared
);
503 config
.llvm_targets
= llvm
.targets
.clone();
504 config
.llvm_experimental_targets
= llvm
.experimental_targets
.clone()
505 .unwrap_or("WebAssembly".to_string());
506 config
.llvm_link_jobs
= llvm
.link_jobs
;
509 if let Some(ref rust
) = toml
.rust
{
511 debug_assertions
= rust
.debug_assertions
;
512 debuginfo
= rust
.debuginfo
;
513 debuginfo_lines
= rust
.debuginfo_lines
;
514 debuginfo_only_std
= rust
.debuginfo_only_std
;
515 debuginfo_tools
= rust
.debuginfo_tools
;
516 optimize
= rust
.optimize
;
517 ignore_git
= rust
.ignore_git
;
518 debug_jemalloc
= rust
.debug_jemalloc
;
519 set(&mut config
.rust_optimize_tests
, rust
.optimize_tests
);
520 set(&mut config
.rust_debuginfo_tests
, rust
.debuginfo_tests
);
521 set(&mut config
.codegen_tests
, rust
.codegen_tests
);
522 set(&mut config
.rust_rpath
, rust
.rpath
);
523 set(&mut config
.use_jemalloc
, rust
.use_jemalloc
);
524 set(&mut config
.backtrace
, rust
.backtrace
);
525 set(&mut config
.channel
, rust
.channel
.clone());
526 set(&mut config
.rust_dist_src
, rust
.dist_src
);
527 set(&mut config
.quiet_tests
, rust
.quiet_tests
);
528 set(&mut config
.test_miri
, rust
.test_miri
);
529 set(&mut config
.wasm_syscall
, rust
.wasm_syscall
);
530 set(&mut config
.lld_enabled
, rust
.lld
);
531 config
.rustc_parallel_queries
= rust
.experimental_parallel_queries
.unwrap_or(false);
532 config
.rustc_default_linker
= rust
.default_linker
.clone();
533 config
.musl_root
= rust
.musl_root
.clone().map(PathBuf
::from
);
534 config
.save_toolstates
= rust
.save_toolstates
.clone().map(PathBuf
::from
);
535 set(&mut config
.deny_warnings
, rust
.deny_warnings
.or(flags
.warnings
));
536 set(&mut config
.backtrace_on_ice
, rust
.backtrace_on_ice
);
538 if let Some(ref backends
) = rust
.codegen_backends
{
539 config
.rust_codegen_backends
= backends
.iter()
540 .map(|s
| INTERNER
.intern_str(s
))
544 set(&mut config
.rust_codegen_backends_dir
, rust
.codegen_backends_dir
.clone());
546 match rust
.codegen_units
{
547 Some(0) => config
.rust_codegen_units
= Some(num_cpus
::get() as u32),
548 Some(n
) => config
.rust_codegen_units
= Some(n
),
553 if let Some(ref t
) = toml
.target
{
554 for (triple
, cfg
) in t
{
555 let mut target
= Target
::default();
557 if let Some(ref s
) = cfg
.llvm_config
{
558 target
.llvm_config
= Some(config
.src
.join(s
));
560 if let Some(ref s
) = cfg
.jemalloc
{
561 target
.jemalloc
= Some(config
.src
.join(s
));
563 if let Some(ref s
) = cfg
.android_ndk
{
564 target
.ndk
= Some(config
.src
.join(s
));
566 target
.cc
= cfg
.cc
.clone().map(PathBuf
::from
);
567 target
.cxx
= cfg
.cxx
.clone().map(PathBuf
::from
);
568 target
.ar
= cfg
.ar
.clone().map(PathBuf
::from
);
569 target
.linker
= cfg
.linker
.clone().map(PathBuf
::from
);
570 target
.crt_static
= cfg
.crt_static
.clone();
571 target
.musl_root
= cfg
.musl_root
.clone().map(PathBuf
::from
);
572 target
.qemu_rootfs
= cfg
.qemu_rootfs
.clone().map(PathBuf
::from
);
574 config
.target_config
.insert(INTERNER
.intern_string(triple
.clone()), target
);
578 if let Some(ref t
) = toml
.dist
{
579 config
.dist_sign_folder
= t
.sign_folder
.clone().map(PathBuf
::from
);
580 config
.dist_gpg_password_file
= t
.gpg_password_file
.clone().map(PathBuf
::from
);
581 config
.dist_upload_addr
= t
.upload_addr
.clone();
582 set(&mut config
.rust_dist_src
, t
.src_tarball
);
585 // Now that we've reached the end of our configuration, infer the
586 // default values for all options that we haven't otherwise stored yet.
588 set(&mut config
.initial_rustc
, build
.rustc
.map(PathBuf
::from
));
589 set(&mut config
.initial_cargo
, build
.cargo
.map(PathBuf
::from
));
592 config
.llvm_assertions
= llvm_assertions
.unwrap_or(default);
594 let default = match &config
.channel
[..] {
595 "stable" | "beta" | "nightly" => true,
598 config
.rust_debuginfo_lines
= debuginfo_lines
.unwrap_or(default);
599 config
.rust_debuginfo_only_std
= debuginfo_only_std
.unwrap_or(default);
600 config
.rust_debuginfo_tools
= debuginfo_tools
.unwrap_or(false);
602 let default = debug
== Some(true);
603 config
.debug_jemalloc
= debug_jemalloc
.unwrap_or(default);
604 config
.rust_debuginfo
= debuginfo
.unwrap_or(default);
605 config
.rust_debug_assertions
= debug_assertions
.unwrap_or(default);
606 config
.rust_optimize
= optimize
.unwrap_or(!default);
608 let default = config
.channel
== "dev";
609 config
.ignore_git
= ignore_git
.unwrap_or(default);
614 /// Try to find the relative path of `libdir`.
615 pub fn libdir_relative(&self) -> Option
<&Path
> {
616 let libdir
= self.libdir
.as_ref()?
;
617 if libdir
.is_relative() {
620 // Try to make it relative to the prefix.
621 libdir
.strip_prefix(self.prefix
.as_ref()?
).ok()
625 pub fn verbose(&self) -> bool
{
629 pub fn very_verbose(&self) -> bool
{
634 fn set
<T
>(field
: &mut T
, val
: Option
<T
>) {
635 if let Some(v
) = val
{