Skip to content

Commit c6b9324

Browse files
committed
Auto merge of #1441 - alexcrichton:issue-1323, r=bson
This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2 parents 8d4bf72 + 0c28783 commit c6b9324

32 files changed

+1163
-1017
lines changed

src/bin/bench.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,31 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
5050
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
5151
config.shell().set_verbose(options.flag_verbose);
5252

53+
let mut benches = Vec::new();
54+
if let Some(s) = options.flag_bench {
55+
benches.push(s);
56+
}
57+
5358
let ops = ops::TestOptions {
54-
name: options.flag_bench.as_ref().map(|s| &s[..]),
5559
no_run: options.flag_no_run,
5660
compile_opts: ops::CompileOptions {
57-
env: "bench",
5861
config: config,
5962
jobs: options.flag_jobs,
6063
target: options.flag_target.as_ref().map(|s| &s[..]),
61-
dev_deps: true,
6264
features: &options.flag_features,
6365
no_default_features: options.flag_no_default_features,
6466
spec: options.flag_package.as_ref().map(|s| &s[..]),
65-
lib_only: false,
6667
exec_engine: None,
68+
release: true,
69+
mode: ops::CompileMode::Bench,
70+
filter: if benches.is_empty() {
71+
ops::CompileFilter::Everything
72+
} else {
73+
ops::CompileFilter::Only {
74+
lib: false, bins: &[], examples: &[], tests: &[],
75+
benches: &benches,
76+
}
77+
},
6778
},
6879
};
6980

src/bin/build.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,29 @@ the --release flag will use the `release` profile instead.
4747
";
4848

4949
pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
50-
debug!("executing; cmd=cargo-build; args={:?}", env::args().collect::<Vec<_>>());
50+
debug!("executing; cmd=cargo-build; args={:?}",
51+
env::args().collect::<Vec<_>>());
5152
config.shell().set_verbose(options.flag_verbose);
5253

5354
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
5455

55-
let env = if options.flag_release {
56-
"release"
57-
} else {
58-
"compile"
59-
};
60-
6156
let opts = CompileOptions {
62-
env: env,
6357
config: config,
6458
jobs: options.flag_jobs,
6559
target: options.flag_target.as_ref().map(|t| &t[..]),
66-
dev_deps: false,
6760
features: &options.flag_features,
6861
no_default_features: options.flag_no_default_features,
6962
spec: options.flag_package.as_ref().map(|s| &s[..]),
70-
lib_only: options.flag_lib,
7163
exec_engine: None,
64+
mode: ops::CompileMode::Build,
65+
release: options.flag_release,
66+
filter: if options.flag_lib {
67+
ops::CompileFilter::Only {
68+
lib: true, bins: &[], examples: &[], benches: &[], tests: &[]
69+
}
70+
} else {
71+
ops::CompileFilter::Everything
72+
},
7273
};
7374

7475
ops::compile(&root, &opts).map(|_| None).map_err(|err| {

src/bin/cargo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
105105
// For the commands `cargo` and `cargo help`, re-execute ourselves as
106106
// `cargo -h` so we can go through the normal process of printing the
107107
// help message.
108-
"" | "help" if flags.arg_args.len() == 0 => {
108+
"" | "help" if flags.arg_args.is_empty() => {
109109
config.shell().set_verbose(true);
110110
let args = &["cargo".to_string(), "-h".to_string()];
111111
let r = cargo::call_main_without_stdin(execute, config, USAGE, args,

src/bin/doc.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,20 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
4646
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
4747

4848
let mut doc_opts = ops::DocOptions {
49-
all: !options.flag_no_deps,
5049
open_result: options.flag_open,
5150
compile_opts: ops::CompileOptions {
52-
env: if options.flag_no_deps {"doc"} else {"doc-all"},
5351
config: config,
5452
jobs: options.flag_jobs,
5553
target: None,
56-
dev_deps: false,
5754
features: &options.flag_features,
5855
no_default_features: options.flag_no_default_features,
5956
spec: options.flag_package.as_ref().map(|s| &s[..]),
60-
lib_only: false,
6157
exec_engine: None,
58+
filter: ops::CompileFilter::Everything,
59+
release: false,
60+
mode: ops::CompileMode::Doc {
61+
deps: !options.flag_no_deps,
62+
},
6263
},
6364
};
6465

src/bin/run.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use cargo::ops;
2-
use cargo::core::manifest::TargetKind;
3-
use cargo::util::{CliResult, CliError, human, Config};
2+
use cargo::util::{CliResult, CliError, Config};
43
use cargo::util::important_paths::{find_root_manifest_for_cwd};
54

65
#[derive(RustcDecodable)]
@@ -47,36 +46,35 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
4746
config.shell().set_verbose(options.flag_verbose);
4847
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
4948

50-
let env = match (options.flag_release, options.flag_example.is_some()) {
51-
(true, _) => "release",
52-
(false, true) => "test",
53-
(false, false) => "compile"
54-
};
49+
let (mut examples, mut bins) = (Vec::new(), Vec::new());
50+
if let Some(s) = options.flag_bin {
51+
bins.push(s);
52+
}
53+
if let Some(s) = options.flag_example {
54+
examples.push(s);
55+
}
5556

5657
let compile_opts = ops::CompileOptions {
57-
env: env,
5858
config: config,
5959
jobs: options.flag_jobs,
6060
target: options.flag_target.as_ref().map(|t| &t[..]),
61-
dev_deps: true,
6261
features: &options.flag_features,
6362
no_default_features: options.flag_no_default_features,
6463
spec: None,
65-
lib_only: false,
6664
exec_engine: None,
67-
};
68-
69-
let (target_kind, name) = match (options.flag_bin, options.flag_example) {
70-
(Some(bin), None) => (TargetKind::Bin, Some(bin)),
71-
(None, Some(example)) => (TargetKind::Example, Some(example)),
72-
(None, None) => (TargetKind::Bin, None),
73-
(Some(_), Some(_)) => return Err(CliError::from_boxed(
74-
human("specify either `--bin` or `--example`, not both"), 1)),
65+
release: options.flag_release,
66+
mode: ops::CompileMode::Build,
67+
filter: if examples.is_empty() && bins.is_empty() {
68+
ops::CompileFilter::Everything
69+
} else {
70+
ops::CompileFilter::Only {
71+
lib: false, tests: &[], benches: &[],
72+
bins: &bins, examples: &examples,
73+
}
74+
},
7575
};
7676

7777
let err = try!(ops::run(&root,
78-
target_kind,
79-
name,
8078
&compile_opts,
8179
&options.arg_args).map_err(|err| {
8280
CliError::from_boxed(err, 101)

src/bin/test.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct Options {
99
flag_jobs: Option<u32>,
1010
flag_manifest_path: Option<String>,
1111
flag_test: Option<String>,
12+
flag_bin: Option<String>,
1213
flag_no_default_features: bool,
1314
flag_no_run: bool,
1415
flag_package: Option<String>,
@@ -24,7 +25,8 @@ Usage:
2425
2526
Options:
2627
-h, --help Print this message
27-
--test NAME Name of the test executable to run
28+
--test NAME Name of the integration test to run
29+
--bin NAME Name of the binary to run tests for
2830
--no-run Compile, but don't run tests
2931
-p SPEC, --package SPEC Package to run tests for
3032
-j N, --jobs N The number of jobs to run in parallel
@@ -52,20 +54,34 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
5254
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
5355
config.shell().set_verbose(options.flag_verbose);
5456

57+
let (mut tests, mut bins) = (Vec::new(), Vec::new());
58+
if let Some(s) = options.flag_test {
59+
tests.push(s);
60+
}
61+
if let Some(s) = options.flag_bin {
62+
bins.push(s);
63+
}
64+
5565
let ops = ops::TestOptions {
56-
name: options.flag_test.as_ref().map(|s| &s[..]),
5766
no_run: options.flag_no_run,
5867
compile_opts: ops::CompileOptions {
59-
env: "test",
6068
config: config,
6169
jobs: options.flag_jobs,
6270
target: options.flag_target.as_ref().map(|s| &s[..]),
63-
dev_deps: true,
6471
features: &options.flag_features,
6572
no_default_features: options.flag_no_default_features,
6673
spec: options.flag_package.as_ref().map(|s| &s[..]),
67-
lib_only: false,
6874
exec_engine: None,
75+
release: false,
76+
mode: ops::CompileMode::Test,
77+
filter: if tests.is_empty() && bins.is_empty() {
78+
ops::CompileFilter::Everything
79+
} else {
80+
ops::CompileFilter::Only {
81+
lib: false, examples: &[], benches: &[],
82+
tests: &tests, bins: &bins,
83+
}
84+
}
6985
},
7086
};
7187

0 commit comments

Comments
 (0)