Skip to content

Commit d6b26a2

Browse files
committed
Add build profile.
1 parent c866f48 commit d6b26a2

File tree

6 files changed

+635
-39
lines changed

6 files changed

+635
-39
lines changed

src/cargo/core/features.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ features! {
191191
// Overriding profiles for dependencies.
192192
[unstable] profile_overrides: bool,
193193

194+
// Build profile.
195+
[unstable] build_profile: bool,
196+
194197
// Separating the namespaces for features and dependencies
195198
[unstable] namespaced_features: bool,
196199

src/cargo/core/profiles.rs

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use std::collections::HashSet;
2+
use std::path::Path;
23
use std::{cmp, env, fmt, hash};
34

45
use serde::Deserialize;
56

67
use crate::core::compiler::CompileMode;
78
use crate::core::interning::InternedString;
8-
use crate::core::{Features, PackageId, PackageIdSpec, PackageSet, Shell};
9+
use crate::core::{Feature, Features, PackageId, PackageIdSpec, PackageSet, Shell};
910
use crate::util::errors::CargoResultExt;
1011
use crate::util::lev_distance::lev_distance;
1112
use crate::util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool};
@@ -19,10 +20,13 @@ pub struct Profiles {
1920
test: ProfileMaker,
2021
bench: ProfileMaker,
2122
doc: ProfileMaker,
23+
build: ProfileMaker,
2224
/// Incremental compilation can be overridden globally via:
2325
/// - `CARGO_INCREMENTAL` environment variable.
2426
/// - `build.incremental` config value.
2527
incremental: Option<bool>,
28+
// Temporary flag to detect if unstable feature is enabled.
29+
build_enabled: bool,
2630
}
2731

2832
impl Profiles {
@@ -31,9 +35,13 @@ impl Profiles {
3135
config: &Config,
3236
features: &Features,
3337
warnings: &mut Vec<String>,
38+
manifest_path: &Path,
3439
) -> CargoResult<Profiles> {
3540
if let Some(profiles) = profiles {
3641
profiles.validate(features, warnings)?;
42+
if profiles.build.is_some() {
43+
features.require(Feature::build_profile())?;
44+
}
3745
}
3846

3947
let config_profiles = config.profiles()?;
@@ -43,6 +51,18 @@ impl Profiles {
4351
None => config.get::<Option<bool>>("build.incremental")?,
4452
};
4553

54+
let config_build_profile =
55+
if !features.is_enabled(Feature::build_profile()) && config_profiles.build.is_some() {
56+
warnings.push(format!(
57+
"profile `build` in config file will be ignored for \
58+
manifest `{}` because \"build-profile\" feature is not enabled",
59+
manifest_path.display()
60+
));
61+
None
62+
} else {
63+
config_profiles.build.clone()
64+
};
65+
4666
Ok(Profiles {
4767
dev: ProfileMaker {
4868
default: Profile::default_dev(),
@@ -69,7 +89,13 @@ impl Profiles {
6989
toml: profiles.and_then(|p| p.doc.clone()),
7090
config: None,
7191
},
92+
build: ProfileMaker {
93+
default: Profile::default_build(),
94+
toml: profiles.and_then(|p| p.build.clone()),
95+
config: config_build_profile,
96+
},
7297
incremental,
98+
build_enabled: features.is_enabled(Feature::build_profile()),
7399
})
74100
}
75101

@@ -100,10 +126,14 @@ impl Profiles {
100126
// `build_unit_profiles` normally ensures that it selects the
101127
// ancestor's profile. However, `cargo clean -p` can hit this
102128
// path.
103-
if release {
104-
&self.release
129+
let maker = if release { &self.release } else { &self.dev };
130+
if (unit_for.build)
131+
&& self.build_enabled
132+
&& !maker.has_build_override()
133+
{
134+
&self.build
105135
} else {
106-
&self.dev
136+
maker
107137
}
108138
}
109139
CompileMode::Doc { .. } => &self.doc,
@@ -148,9 +178,11 @@ impl Profiles {
148178
/// select for the package that was actually built.
149179
pub fn base_profile(&self, release: bool) -> Profile {
150180
if release {
151-
self.release.get_profile(None, true, UnitFor::new_normal())
181+
self.release
182+
.get_profile(None, true, UnitFor::new_normal())
152183
} else {
153-
self.dev.get_profile(None, true, UnitFor::new_normal())
184+
self.dev
185+
.get_profile(None, true, UnitFor::new_normal())
154186
}
155187
}
156188

@@ -165,6 +197,7 @@ impl Profiles {
165197
self.test.validate_packages(shell, packages)?;
166198
self.bench.validate_packages(shell, packages)?;
167199
self.doc.validate_packages(shell, packages)?;
200+
self.build.validate_packages(shell, packages)?;
168201
Ok(())
169202
}
170203
}
@@ -198,10 +231,22 @@ impl ProfileMaker {
198231
) -> Profile {
199232
let mut profile = self.default;
200233
if let Some(ref toml) = self.toml {
201-
merge_toml(pkg_id, is_member, unit_for, &mut profile, toml);
234+
merge_toml(
235+
pkg_id,
236+
is_member,
237+
unit_for,
238+
&mut profile,
239+
toml,
240+
);
202241
}
203242
if let Some(ref toml) = self.config {
204-
merge_toml(pkg_id, is_member, unit_for, &mut profile, toml);
243+
merge_toml(
244+
pkg_id,
245+
is_member,
246+
unit_for,
247+
&mut profile,
248+
toml,
249+
);
205250
}
206251
profile
207252
}
@@ -318,6 +363,13 @@ impl ProfileMaker {
318363
}
319364
Ok(())
320365
}
366+
367+
fn has_build_override(&self) -> bool {
368+
self.toml
369+
.as_ref()
370+
.map(|tp| tp.build_override.is_some())
371+
.unwrap_or(false)
372+
}
321373
}
322374

323375
fn merge_toml(
@@ -449,6 +501,7 @@ compact_debug! {
449501
"test" => (Profile::default_test(), "default_test()"),
450502
"bench" => (Profile::default_bench(), "default_bench()"),
451503
"doc" => (Profile::default_doc(), "default_doc()"),
504+
"build" => (Profile::default_build(), "default_build()"),
452505
_ => (Profile::default(), "default()"),
453506
};
454507
[debug_the_fields(
@@ -529,6 +582,13 @@ impl Profile {
529582
}
530583
}
531584

585+
fn default_build() -> Profile {
586+
Profile {
587+
name: "build",
588+
..Profile::default()
589+
}
590+
}
591+
532592
/// Compares all fields except `name`, which doesn't affect compilation.
533593
/// This is necessary for `Unit` deduplication for things like "test" and
534594
/// "dev" which are essentially the same.
@@ -604,31 +664,33 @@ pub struct UnitFor {
604664
impl UnitFor {
605665
/// A unit for a normal target/dependency (i.e., not custom build,
606666
/// proc macro/plugin, or test/bench).
607-
pub fn new_normal() -> UnitFor {
667+
pub const fn new_normal() -> UnitFor {
608668
UnitFor {
609669
build: false,
610670
panic_abort_ok: true,
611671
}
612672
}
613673

614674
/// A unit for a custom build script or its dependencies.
615-
pub fn new_build() -> UnitFor {
675+
pub const fn new_build() -> UnitFor {
616676
UnitFor {
617677
build: true,
618678
panic_abort_ok: false,
619679
}
620680
}
621681

622682
/// A unit for a proc macro or compiler plugin or their dependencies.
623-
pub fn new_compiler() -> UnitFor {
683+
pub const fn new_compiler() -> UnitFor {
684+
// Note: This is currently the same as `new_build`, but keeping it
685+
// separate for now in case it is useful in the future.
624686
UnitFor {
625-
build: false,
687+
build: true,
626688
panic_abort_ok: false,
627689
}
628690
}
629691

630692
/// A unit for a test/bench target or their dependencies.
631-
pub fn new_test() -> UnitFor {
693+
pub const fn new_test() -> UnitFor {
632694
UnitFor {
633695
build: false,
634696
panic_abort_ok: false,
@@ -660,18 +722,9 @@ impl UnitFor {
660722
/// All possible values, used by `clean`.
661723
pub fn all_values() -> &'static [UnitFor] {
662724
static ALL: [UnitFor; 3] = [
663-
UnitFor {
664-
build: false,
665-
panic_abort_ok: true,
666-
},
667-
UnitFor {
668-
build: true,
669-
panic_abort_ok: false,
670-
},
671-
UnitFor {
672-
build: false,
673-
panic_abort_ok: false,
674-
},
725+
UnitFor::new_normal(),
726+
UnitFor::new_build(),
727+
UnitFor::new_test(),
675728
];
676729
&ALL
677730
}
@@ -682,22 +735,29 @@ impl UnitFor {
682735
pub struct ConfigProfiles {
683736
dev: Option<TomlProfile>,
684737
release: Option<TomlProfile>,
738+
build: Option<TomlProfile>,
685739
}
686740

687741
impl ConfigProfiles {
688742
pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> {
689-
if let Some(ref profile) = self.dev {
690-
profile
691-
.validate("dev", features, warnings)
692-
.chain_err(|| failure::format_err!("config profile `profile.dev` is not valid"))?;
693-
}
694-
if let Some(ref profile) = self.release {
695-
profile
696-
.validate("release", features, warnings)
697-
.chain_err(|| {
698-
failure::format_err!("config profile `profile.release` is not valid")
699-
})?;
743+
macro_rules! check_profile {
744+
($name:ident) => {
745+
if let Some(ref profile) = self.$name {
746+
profile
747+
.validate(stringify!($name), features, warnings)
748+
.chain_err(|| {
749+
failure::format_err!(
750+
"config profile `profile.{}` is not valid",
751+
stringify!($name)
752+
)
753+
})?;
754+
}
755+
};
700756
}
757+
758+
check_profile!(dev);
759+
check_profile!(release);
760+
check_profile!(build);
701761
Ok(())
702762
}
703763
}

src/cargo/util/toml/mod.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ pub struct TomlProfiles {
275275
pub bench: Option<TomlProfile>,
276276
pub dev: Option<TomlProfile>,
277277
pub release: Option<TomlProfile>,
278+
pub build: Option<TomlProfile>,
278279
}
279280

280281
impl TomlProfiles {
@@ -294,6 +295,9 @@ impl TomlProfiles {
294295
if let Some(ref release) = self.release {
295296
release.validate("release", features, warnings)?;
296297
}
298+
if let Some(ref build) = self.build {
299+
build.validate("build", features, warnings)?;
300+
}
297301
Ok(())
298302
}
299303
}
@@ -470,7 +474,7 @@ impl TomlProfile {
470474
}
471475

472476
match name {
473-
"dev" | "release" => {}
477+
"dev" | "release" | "build" => {}
474478
_ => {
475479
if self.overrides.is_some() || self.build_override.is_some() {
476480
bail!(
@@ -491,6 +495,11 @@ impl TomlProfile {
491495
warnings.push(format!("`panic` setting is ignored for `{}` profile", name))
492496
}
493497
}
498+
"build" => {
499+
if self.build_override.is_some() {
500+
failure::bail!("`build` profile cannot specify build overrides.")
501+
}
502+
}
494503
_ => {}
495504
}
496505

@@ -1023,7 +1032,13 @@ impl TomlManifest {
10231032
`[workspace]`, only one can be specified"
10241033
),
10251034
};
1026-
let profiles = Profiles::new(me.profile.as_ref(), config, &features, &mut warnings)?;
1035+
let profiles = Profiles::new(
1036+
me.profile.as_ref(),
1037+
config,
1038+
&features,
1039+
&mut warnings,
1040+
&package_root.join("Cargo.toml"),
1041+
)?;
10271042
let publish = match project.publish {
10281043
Some(VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()),
10291044
Some(VecStringOrBool::Bool(false)) => Some(vec![]),
@@ -1154,7 +1169,13 @@ impl TomlManifest {
11541169
};
11551170
(me.replace(&mut cx)?, me.patch(&mut cx)?)
11561171
};
1157-
let profiles = Profiles::new(me.profile.as_ref(), config, &features, &mut warnings)?;
1172+
let profiles = Profiles::new(
1173+
me.profile.as_ref(),
1174+
config,
1175+
&features,
1176+
&mut warnings,
1177+
&root.join("Cargo.toml"),
1178+
)?;
11581179
let workspace_config = match me.workspace {
11591180
Some(ref config) => WorkspaceConfig::Root(WorkspaceRootConfig::new(
11601181
root,

src/doc/src/reference/unstable.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,36 @@ cargo +nightly build -Z config-profile
148148
```
149149

150150

151+
### Build Profile
152+
* Tracking Issue: [rust-lang/rust#48683](https://github.com/rust-lang/rust/issues/48683)
153+
154+
The `build` profile controls the build settings for build scripts,
155+
proc-macros, compiler plugins, and all of their dependencies. It requires the
156+
`build-profile` feature to be enabled.
157+
158+
```toml
159+
cargo-features = ["build-profile"]
160+
161+
[profile.build]
162+
# The following illustrates the defaults.
163+
opt-level = 0
164+
debug = false
165+
rpath = false
166+
lto = false
167+
debug-assertions = false
168+
codegen-units = 16
169+
panic = 'unwind'
170+
incremental = false
171+
overflow-checks = false
172+
```
173+
174+
It is compatible with [Profile Overrides](#profile-overrides) and [Config
175+
Profiles](#config-profiles). If `build-override` is specified in a dev or
176+
release profile, that takes precedence over the `build` profile. Enabling
177+
`build-profile` will cause `build-override` to also affect proc-macros and
178+
plugins (normally it only affects build scripts).
179+
180+
151181
### Namespaced features
152182
* Original issue: [#1286](https://github.com/rust-lang/cargo/issues/1286)
153183
* Tracking Issue: [#5565](https://github.com/rust-lang/cargo/issues/5565)

0 commit comments

Comments
 (0)