// is currently just a hack and will be removed eventually, so please
// try to not rely on this too much.
actually_rustdoc: bool [TRACKED],
+
+ // Number of object files/codegen units to produce on the backend
+ codegen_units: usize [UNTRACKED],
}
);
unstable_features: UnstableFeatures::Disallow,
debug_assertions: true,
actually_rustdoc: false,
+ codegen_units: 1,
}
}
(self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
}
- pub fn single_codegen_unit(&self) -> bool {
- self.incremental.is_none() ||
- self.cg.codegen_units == 1
- }
-
pub fn file_path_mapping(&self) -> FilePathMapping {
FilePathMapping::new(
self.debugging_opts.remap_path_prefix_from.iter().zip(
fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = s.parse().ok(); slot.is_some() }
- None => { *slot = None; true }
+ None => { *slot = None; false }
}
}
"metadata to mangle symbol names with"),
extra_filename: String = ("".to_string(), parse_string, [UNTRACKED],
"extra data to put in each output filename"),
- codegen_units: usize = (1, parse_uint, [UNTRACKED],
+ codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
"divide crate into N units to optimize in parallel"),
remark: Passes = (SomePasses(Vec::new()), parse_passes, [UNTRACKED],
"print remarks for these optimization passes (space separated, or \"all\")"),
}
let mut cg = build_codegen_options(matches, error_format);
+ let mut codegen_units = cg.codegen_units;
// Issue #30063: if user requests llvm-related output to one
// particular path, disable codegen-units.
- if matches.opt_present("o") && cg.codegen_units != 1 {
- let incompatible: Vec<_> = output_types.iter()
- .map(|ot_path| ot_path.0)
- .filter(|ot| {
- !ot.is_compatible_with_codegen_units_and_single_output_file()
- }).collect();
- if !incompatible.is_empty() {
- for ot in &incompatible {
- early_warn(error_format, &format!("--emit={} with -o incompatible with \
- -C codegen-units=N for N > 1",
- ot.shorthand()));
+ let incompatible: Vec<_> = output_types.iter()
+ .map(|ot_path| ot_path.0)
+ .filter(|ot| {
+ !ot.is_compatible_with_codegen_units_and_single_output_file()
+ })
+ .map(|ot| ot.shorthand())
+ .collect();
+ if !incompatible.is_empty() {
+ match codegen_units {
+ Some(n) if n > 1 => {
+ if matches.opt_present("o") {
+ for ot in &incompatible {
+ early_warn(error_format, &format!("--emit={} with -o incompatible with \
+ -C codegen-units=N for N > 1",
+ ot));
+ }
+ early_warn(error_format, "resetting to default -C codegen-units=1");
+ codegen_units = Some(1);
+ }
}
- early_warn(error_format, "resetting to default -C codegen-units=1");
- cg.codegen_units = 1;
+ _ => codegen_units = Some(1),
}
}
- if cg.codegen_units < 1 {
+ if codegen_units == Some(0) {
early_error(error_format, "Value for codegen units must be a positive nonzero integer");
}
// case, but it would be confusing to have the validity of
// `-Z lto -C codegen-units=2` depend on details of the crate being
// compiled, so we complain regardless.
- if cg.lto && cg.codegen_units > 1 {
- // This case is impossible to handle because LTO expects to be able
- // to combine the entire crate and all its dependencies into a
- // single compilation unit, but each codegen unit is in a separate
- // LLVM context, so they can't easily be combined.
- early_error(error_format, "can't perform LTO when using multiple codegen units");
+ if cg.lto {
+ if let Some(n) = codegen_units {
+ if n > 1 {
+ // This case is impossible to handle because LTO expects to be able
+ // to combine the entire crate and all its dependencies into a
+ // single compilation unit, but each codegen unit is in a separate
+ // LLVM context, so they can't easily be combined.
+ early_error(error_format, "can't perform LTO when using multiple codegen units");
+ }
+ }
+ codegen_units = Some(1);
}
if cg.lto && debugging_opts.incremental.is_some() {
let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
+ let codegen_units = codegen_units.unwrap_or_else(|| {
+ match opt_level {
+ // If we're compiling at `-O0` then default to 32 codegen units.
+ // The number here shouldn't matter too too much as debug mode
+ // builds don't rely on performance at all, meaning that lost
+ // opportunities for inlining through multiple codegen units is
+ // a non-issue.
+ //
+ // Note that the high number here doesn't mean that we'll be
+ // spawning a large number of threads in parallel. The backend
+ // of rustc contains global rate limiting through the
+ // `jobserver` crate so we'll never overload the system with too
+ // much work, but rather we'll only be optimizing when we're
+ // otherwise cooperating with other instances of rustc.
+ //
+ // Rather the high number here means that we should be able to
+ // keep a lot of idle cpus busy. By ensuring that no codegen
+ // unit takes *too* long to build we'll be guaranteed that all
+ // cpus will finish pretty closely to one another and we should
+ // make relatively optimal use of system resources
+ OptLevel::No => 32,
+
+ // All other optimization levels default use one codegen unit,
+ // the historical default in Rust for a Long Time.
+ _ => 1,
+ }
+ });
+
(Options {
crate_types,
optimize: opt_level,
unstable_features: UnstableFeatures::from_environment(),
debug_assertions,
actually_rustdoc: false,
+ codegen_units,
},
cfg)
}
opts.cg.extra_filename = String::from("extra-filename");
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
- opts.cg.codegen_units = 42;
+ opts.cg.codegen_units = Some(42);
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
opts.cg.remark = super::SomePasses(vec![String::from("pass1"),
-include ../tools.mk
+LOG = $(TMPDIR)/log.txt
+
all:
#Option taking a number
- $(RUSTC) -C codegen-units dummy.rs 2>&1 | \
- grep 'codegen option `codegen-units` requires a number'
- $(RUSTC) -C codegen-units= dummy.rs 2>&1 | \
- grep 'incorrect value `` for codegen option `codegen-units` - a number was expected'
- $(RUSTC) -C codegen-units=foo dummy.rs 2>&1 | \
- grep 'incorrect value `foo` for codegen option `codegen-units` - a number was expected'
+ $(RUSTC) -C codegen-units dummy.rs 2>&1 | tee $(LOG)
+ grep 'codegen option `codegen-units` requires a number' $(LOG)
+ $(RUSTC) -C codegen-units= dummy.rs 2>&1 | tee $(LOG)
+ grep 'incorrect value `` for codegen option `codegen-units` - a number was expected' $(LOG)
+ $(RUSTC) -C codegen-units=foo dummy.rs 2>&1 | tee $(LOG)
+ grep 'incorrect value `foo` for codegen option `codegen-units` - a number was expected' $(LOG)
$(RUSTC) -C codegen-units=1 dummy.rs
#Option taking a string
- $(RUSTC) -C extra-filename dummy.rs 2>&1 | \
- grep 'codegen option `extra-filename` requires a string'
+ $(RUSTC) -C extra-filename dummy.rs 2>&1 | tee $(LOG)
+ grep 'codegen option `extra-filename` requires a string' $(LOG)
$(RUSTC) -C extra-filename= dummy.rs 2>&1
$(RUSTC) -C extra-filename=foo dummy.rs 2>&1
#Option taking no argument
- $(RUSTC) -C lto= dummy.rs 2>&1 | \
- grep 'codegen option `lto` takes no value'
- $(RUSTC) -C lto=1 dummy.rs 2>&1 | \
- grep 'codegen option `lto` takes no value'
- $(RUSTC) -C lto=foo dummy.rs 2>&1 | \
- grep 'codegen option `lto` takes no value'
+ $(RUSTC) -C lto= dummy.rs 2>&1 | tee $(LOG)
+ grep 'codegen option `lto` takes no value' $(LOG)
+ $(RUSTC) -C lto=1 dummy.rs 2>&1 | tee $(LOG)
+ grep 'codegen option `lto` takes no value' $(LOG)
+ $(RUSTC) -C lto=foo dummy.rs 2>&1 | tee $(LOG)
+ grep 'codegen option `lto` takes no value' $(LOG)
$(RUSTC) -C lto dummy.rs
# Should not link dead code...