Skip to content

Commit e10c651

Browse files
committed
Auto merge of #4817 - alexcrichton:incremental-by-default, r=matklad
Enable incremental by default This commit enables incremental compilation by default in Cargo for all dev-related profiles (aka anything without `--release` or `bench`. A number of new configuration options were also added to tweak how incremental compilation is exposed and/or used: * A `profile.dev.incremental` field is added to `Cargo.toml` to disable it on a per-project basis (in case of bugs). * A `build.incremental` field was added in `.cargo/config` to disable globally (or enable if we flip this default back off). Otherwise `CARGO_INCREMENTAL` can still be used to configure one particular compilation. The global `build.incremental` configuration cannot currently be used to enable it for the release profile.
2 parents fac7e25 + 45cc30b commit e10c651

File tree

11 files changed

+157
-46
lines changed

11 files changed

+157
-46
lines changed

.travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ matrix:
2828

2929
- env: TARGET=x86_64-unknown-linux-gnu
3030
ALT=i686-unknown-linux-gnu
31-
# FIXME(rust-lang/rust#46271) should use just `nightly`
32-
rust: nightly-2017-11-20
31+
rust: nightly
3332
install:
3433
- mdbook --help || cargo install mdbook --force
3534
script:

src/cargo/core/manifest.rs

+4
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ pub struct Profile {
177177
pub check: bool,
178178
#[serde(skip_serializing)]
179179
pub panic: Option<String>,
180+
#[serde(skip_serializing)]
181+
pub incremental: bool,
180182
}
181183

182184
#[derive(Default, Clone, Debug, PartialEq, Eq)]
@@ -631,6 +633,7 @@ impl Profile {
631633
debuginfo: Some(2),
632634
debug_assertions: true,
633635
overflow_checks: true,
636+
incremental: true,
634637
..Profile::default()
635638
}
636639
}
@@ -712,6 +715,7 @@ impl Default for Profile {
712715
run_custom_build: false,
713716
check: false,
714717
panic: None,
718+
incremental: false,
715719
}
716720
}
717721
}

src/cargo/ops/cargo_rustc/context.rs

+50-34
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub struct Context<'a, 'cfg: 'a> {
100100
target_info: TargetInfo,
101101
host_info: TargetInfo,
102102
profiles: &'a Profiles,
103-
incremental_enabled: bool,
103+
incremental_env: Option<bool>,
104104

105105
/// For each Unit, a list all files produced as a triple of
106106
///
@@ -154,24 +154,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
154154
None => None,
155155
};
156156

157-
// Enable incremental builds if the user opts in. For now,
158-
// this is an environment variable until things stabilize a
159-
// bit more.
160-
let incremental_enabled = match env::var("CARGO_INCREMENTAL") {
161-
Ok(v) => v == "1",
162-
Err(_) => false,
157+
let incremental_env = match env::var("CARGO_INCREMENTAL") {
158+
Ok(v) => Some(v == "1"),
159+
Err(_) => None,
163160
};
164161

165-
// -Z can only be used on nightly builds; other builds complain loudly.
166-
// Since incremental builds only work on nightly anyway, we silently
167-
// ignore CARGO_INCREMENTAL on anything but nightly. This allows users
168-
// to always have CARGO_INCREMENTAL set without getting unexpected
169-
// errors on stable/beta builds.
170-
let is_nightly =
171-
config.rustc()?.verbose_version.contains("-nightly") ||
172-
config.rustc()?.verbose_version.contains("-dev");
173-
let incremental_enabled = incremental_enabled && is_nightly;
174-
175162
// Load up the jobserver that we'll use to manage our parallelism. This
176163
// is the same as the GNU make implementation of a jobserver, and
177164
// intentionally so! It's hoped that we can interact with GNU make and
@@ -206,7 +193,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
206193
build_explicit_deps: HashMap::new(),
207194
links: Links::new(),
208195
used_in_plugin: HashSet::new(),
209-
incremental_enabled: incremental_enabled,
196+
incremental_env,
210197
jobserver: jobserver,
211198
build_script_overridden: HashSet::new(),
212199

@@ -1082,24 +1069,53 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
10821069
}
10831070

10841071
pub fn incremental_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
1085-
if self.incremental_enabled {
1086-
if unit.pkg.package_id().source_id().is_path() {
1087-
// Only enable incremental compilation for sources the user can modify.
1088-
// For things that change infrequently, non-incremental builds yield
1089-
// better performance.
1090-
// (see also https://github.com/rust-lang/cargo/issues/3972)
1091-
return Ok(vec![format!("-Zincremental={}",
1092-
self.layout(unit.kind).incremental().display())]);
1093-
} else if unit.profile.codegen_units.is_none() {
1094-
// For non-incremental builds we set a higher number of
1095-
// codegen units so we get faster compiles. It's OK to do
1096-
// so because the user has already opted into slower
1097-
// runtime code by setting CARGO_INCREMENTAL.
1098-
return Ok(vec![format!("-Ccodegen-units={}", ::num_cpus::get())]);
1099-
}
1072+
// There's a number of ways to configure incremental compilation right
1073+
// now. In order of descending priority (first is highest priority) we
1074+
// have:
1075+
//
1076+
// * `CARGO_INCREMENTAL` - this is blanket used unconditionally to turn
1077+
// on/off incremental compilation for any cargo subcommand. We'll
1078+
// respect this if set.
1079+
// * `build.incremental` - in `.cargo/config` this blanket key can
1080+
// globally for a system configure whether incremental compilation is
1081+
// enabled. Note that setting this to `true` will not actually affect
1082+
// all builds though. For example a `true` value doesn't enable
1083+
// release incremental builds, only dev incremental builds. This can
1084+
// be useful to globally disable incremental compilation like
1085+
// `CARGO_INCREMENTAL`.
1086+
// * `profile.dev.incremental` - in `Cargo.toml` specific profiles can
1087+
// be configured to enable/disable incremental compilation. This can
1088+
// be primarily used to disable incremental when buggy for a project.
1089+
// * Finally, each profile has a default for whether it will enable
1090+
// incremental compilation or not. Primarily development profiles
1091+
// have it enabled by default while release profiles have it disabled
1092+
// by default.
1093+
let global_cfg = self.config.get_bool("build.incremental")?.map(|c| c.val);
1094+
let incremental = match (self.incremental_env, global_cfg, unit.profile.incremental) {
1095+
(Some(v), _, _) => v,
1096+
(None, Some(false), _) => false,
1097+
(None, _, other) => other,
1098+
};
1099+
1100+
if !incremental {
1101+
return Ok(Vec::new())
1102+
}
1103+
1104+
// Only enable incremental compilation for sources the user can
1105+
// modify (aka path sources). For things that change infrequently,
1106+
// non-incremental builds yield better performance in the compiler
1107+
// itself (aka crates.io / git dependencies)
1108+
//
1109+
// (see also https://github.com/rust-lang/cargo/issues/3972)
1110+
if !unit.pkg.package_id().source_id().is_path() {
1111+
return Ok(Vec::new())
11001112
}
11011113

1102-
Ok(vec![])
1114+
let dir = self.layout(unit.kind).incremental().display();
1115+
Ok(vec![
1116+
"-C".to_string(),
1117+
format!("incremental={}", dir),
1118+
])
11031119
}
11041120

11051121
pub fn rustflags_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {

src/cargo/ops/cargo_rustc/fingerprint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ fn calculate<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
408408
let fingerprint = Arc::new(Fingerprint {
409409
rustc: util::hash_u64(&cx.config.rustc()?.verbose_version),
410410
target: util::hash_u64(&unit.target),
411-
profile: util::hash_u64(&unit.profile),
411+
profile: util::hash_u64(&(&unit.profile, cx.incremental_args(unit)?)),
412412
// Note that .0 is hashed here, not .1 which is the cwd. That doesn't
413413
// actually affect the output artifact so there's no need to hash it.
414414
path: util::hash_u64(&super::path_args(cx, unit).0),

src/cargo/ops/cargo_rustc/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ fn rustc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
348348
}.with_extension("d");
349349
let dep_info_loc = fingerprint::dep_info_loc(cx, unit);
350350

351-
rustc.args(&cx.incremental_args(unit)?);
352351
rustc.args(&cx.rustflags_args(unit)?);
353352
let json_messages = cx.build_config.json_messages;
354353
let package_id = unit.pkg.package_id().clone();
@@ -651,7 +650,7 @@ fn prepare_rustc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
651650
unit: &Unit<'a>) -> CargoResult<ProcessBuilder> {
652651
let mut base = cx.compilation.rustc_process(unit.pkg)?;
653652
base.inherit_jobserver(&cx.jobserver);
654-
build_base_args(cx, &mut base, unit, crate_types);
653+
build_base_args(cx, &mut base, unit, crate_types)?;
655654
build_deps_args(&mut base, cx, unit)?;
656655
Ok(base)
657656
}
@@ -743,11 +742,11 @@ fn add_path_args(cx: &Context, unit: &Unit, cmd: &mut ProcessBuilder) {
743742
fn build_base_args<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
744743
cmd: &mut ProcessBuilder,
745744
unit: &Unit<'a>,
746-
crate_types: &[&str]) {
745+
crate_types: &[&str]) -> CargoResult<()> {
747746
let Profile {
748747
ref opt_level, lto, codegen_units, ref rustc_args, debuginfo,
749748
debug_assertions, overflow_checks, rpath, test, doc: _doc,
750-
run_custom_build, ref panic, rustdoc_args: _, check,
749+
run_custom_build, ref panic, rustdoc_args: _, check, incremental: _,
751750
} = *unit.profile;
752751
assert!(!run_custom_build);
753752

@@ -888,6 +887,9 @@ fn build_base_args<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
888887

889888
opt(cmd, "-C", "ar=", cx.ar(unit.kind).map(|s| s.as_ref()));
890889
opt(cmd, "-C", "linker=", cx.linker(unit.kind).map(|s| s.as_ref()));
890+
cmd.args(&cx.incremental_args(unit)?);
891+
892+
Ok(())
891893
}
892894

893895

src/cargo/util/toml/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ pub struct TomlProfile {
338338
panic: Option<String>,
339339
#[serde(rename = "overflow-checks")]
340340
overflow_checks: Option<bool>,
341+
incremental: Option<bool>,
341342
}
342343

343344
#[derive(Clone, Debug, Serialize)]
@@ -1123,7 +1124,7 @@ fn build_profiles(profiles: &Option<TomlProfiles>) -> Profiles {
11231124
fn merge(profile: Profile, toml: Option<&TomlProfile>) -> Profile {
11241125
let &TomlProfile {
11251126
ref opt_level, lto, codegen_units, ref debug, debug_assertions, rpath,
1126-
ref panic, ref overflow_checks,
1127+
ref panic, ref overflow_checks, ref incremental,
11271128
} = match toml {
11281129
Some(toml) => toml,
11291130
None => return profile,
@@ -1149,6 +1150,7 @@ fn build_profiles(profiles: &Option<TomlProfiles>) -> Profiles {
11491150
run_custom_build: profile.run_custom_build,
11501151
check: profile.check,
11511152
panic: panic.clone().or(profile.panic),
1153+
incremental: incremental.unwrap_or(profile.incremental),
11521154
}
11531155
}
11541156
}

src/doc/config.md

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ rustdoc = "rustdoc" # the doc generator tool
102102
target = "triple" # build for the target triple
103103
target-dir = "target" # path of where to place all generated artifacts
104104
rustflags = ["..", ".."] # custom flags to pass to all compiler invocations
105+
incremental = true # whether or not to enable incremental compilation
105106

106107
[term]
107108
verbose = false # whether cargo provides verbose output

src/doc/environment-variables.md

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ system:
2828
* `RUSTFLAGS` - A space-separated list of custom flags to pass to all compiler
2929
invocations that Cargo performs. In contrast with `cargo rustc`, this is
3030
useful for passing a flag to *all* compiler instances.
31+
* `CARGO_INCREMENTAL` - If this is set to 1 then Cargo will force incremental
32+
compilation to be enabled for the current compilation, and when set to 0 it
33+
will force disabling it. If this env var isn't present then Cargo's defaults
34+
will otherwise be used.
3135

3236
Note that Cargo will also read environment variables for `.cargo/config`
3337
configuration values, as described in [that documentation][config-env]

src/doc/manifest.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ license-file = "..."
192192

193193
# Appveyor: `repository` is required. `branch` is optional; default is `master`
194194
# `service` is optional; valid values are `github` (default), `bitbucket`, and
195-
# `gitlab`; `id` is optional; you can specify the appveyor project id if you
195+
# `gitlab`; `id` is optional; you can specify the appveyor project id if you
196196
# want to use that instead. `project_name` is optional; use when the repository
197197
# name differs from the appveyor project name.
198198
appveyor = { repository = "...", branch = "master", service = "github" }
@@ -289,6 +289,7 @@ codegen-units = 1 # if > 1 enables parallel code generation which improves
289289
# compile times, but prevents some optimizations.
290290
# Passes `-C codegen-units`. Ignored when `lto = true`.
291291
panic = 'unwind' # panic strategy (`-C panic=...`), can also be 'abort'
292+
incremental = true # whether or not incremental compilation is enabled
292293

293294
# The release profile, used for `cargo build --release`.
294295
[profile.release]
@@ -299,6 +300,7 @@ lto = false
299300
debug-assertions = false
300301
codegen-units = 1
301302
panic = 'unwind'
303+
incremental = false
302304

303305
# The testing profile, used for `cargo test`.
304306
[profile.test]
@@ -309,6 +311,7 @@ lto = false
309311
debug-assertions = true
310312
codegen-units = 1
311313
panic = 'unwind'
314+
incremental = true
312315

313316
# The benchmarking profile, used for `cargo bench` and `cargo test --release`.
314317
[profile.bench]
@@ -319,6 +322,7 @@ lto = false
319322
debug-assertions = false
320323
codegen-units = 1
321324
panic = 'unwind'
325+
incremental = false
322326

323327
# The documentation profile, used for `cargo doc`.
324328
[profile.doc]
@@ -329,6 +333,7 @@ lto = false
329333
debug-assertions = true
330334
codegen-units = 1
331335
panic = 'unwind'
336+
incremental = true
332337
```
333338

334339
# The `[features]` section

tests/build.rs

+76-2
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,90 @@ fn cargo_compile_incremental() {
5858
assert_that(
5959
p.cargo("build").arg("-v").env("CARGO_INCREMENTAL", "1"),
6060
execs().with_stderr_contains(
61-
"[RUNNING] `rustc [..] -Zincremental=[..][/]target[/]debug[/]incremental`\n")
61+
"[RUNNING] `rustc [..] -C incremental=[..][/]target[/]debug[/]incremental[..]`\n")
6262
.with_status(0));
6363

6464
assert_that(
6565
p.cargo("test").arg("-v").env("CARGO_INCREMENTAL", "1"),
6666
execs().with_stderr_contains(
67-
"[RUNNING] `rustc [..] -Zincremental=[..][/]target[/]debug[/]incremental`\n")
67+
"[RUNNING] `rustc [..] -C incremental=[..][/]target[/]debug[/]incremental[..]`\n")
6868
.with_status(0));
6969
}
7070

71+
#[test]
72+
fn incremental_profile() {
73+
if !is_nightly() {
74+
return
75+
}
76+
77+
let p = project("foo")
78+
.file("Cargo.toml", r#"
79+
[package]
80+
name = "foo"
81+
version = "0.1.0"
82+
authors = []
83+
84+
[profile.dev]
85+
incremental = false
86+
87+
[profile.release]
88+
incremental = true
89+
"#)
90+
.file("src/main.rs", "fn main() {}")
91+
.build();
92+
93+
assert_that(
94+
p.cargo("build").arg("-v").env_remove("CARGO_INCREMENTAL"),
95+
execs().with_stderr_does_not_contain("[..]C incremental=[..]")
96+
.with_status(0));
97+
98+
assert_that(
99+
p.cargo("build").arg("-v").env("CARGO_INCREMENTAL", "1"),
100+
execs().with_stderr_contains("[..]C incremental=[..]")
101+
.with_status(0));
102+
103+
assert_that(
104+
p.cargo("build").arg("--release").arg("-v").env_remove("CARGO_INCREMENTAL"),
105+
execs().with_stderr_contains("[..]C incremental=[..]")
106+
.with_status(0));
107+
108+
assert_that(
109+
p.cargo("build").arg("--release").arg("-v").env("CARGO_INCREMENTAL", "0"),
110+
execs().with_stderr_does_not_contain("[..]C incremental=[..]")
111+
.with_status(0));
112+
}
113+
114+
#[test]
115+
fn incremental_config() {
116+
if !is_nightly() {
117+
return
118+
}
119+
120+
let p = project("foo")
121+
.file("Cargo.toml", r#"
122+
[package]
123+
name = "foo"
124+
version = "0.1.0"
125+
authors = []
126+
"#)
127+
.file("src/main.rs", "fn main() {}")
128+
.file(".cargo/config", r#"
129+
[build]
130+
incremental = false
131+
"#)
132+
.build();
133+
134+
assert_that(
135+
p.cargo("build").arg("-v").env_remove("CARGO_INCREMENTAL"),
136+
execs().with_stderr_does_not_contain("[..]C incremental=[..]")
137+
.with_status(0));
138+
139+
assert_that(
140+
p.cargo("build").arg("-v").env("CARGO_INCREMENTAL", "1"),
141+
execs().with_stderr_contains("[..]C incremental=[..]")
142+
.with_status(0));
143+
}
144+
71145
#[test]
72146
fn cargo_compile_manifest_path() {
73147
let p = project("foo")

0 commit comments

Comments
 (0)