Skip to content

Commit d19e295

Browse files
committed
Auto merge of #5358 - djc:options-build-config, r=matklad
Let CompileOptions create a BuildConfig directly This puts input validation in a more central place and prevents copying/moving stuff around as separate values.
2 parents 07c0784 + 072254c commit d19e295

29 files changed

+472
-463
lines changed

src/bin/cargo/command_prelude.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use std::fs;
44
use clap::{self, SubCommand};
55
use cargo::CargoResult;
66
use cargo::core::Workspace;
7-
use cargo::ops::{CompileFilter, CompileMode, CompileOptions, MessageFormat, NewOptions, Packages,
8-
VersionControl};
7+
use cargo::core::compiler::{BuildConfig, MessageFormat};
8+
use cargo::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
99
use cargo::util::paths;
1010
use cargo::util::important_paths::find_root_manifest_for_wd;
1111

1212
pub use clap::{AppSettings, Arg, ArgMatches};
1313
pub use cargo::{CliError, CliResult, Config};
14+
pub use cargo::core::compiler::CompileMode;
1415

1516
pub type App = clap::App<'static, 'static>;
1617

@@ -271,16 +272,17 @@ pub trait ArgMatchesExt {
271272
}
272273
};
273274

275+
let mut build_config = BuildConfig::new(config, self.jobs()?, &self.target(), mode)?;
276+
build_config.message_format = message_format;
277+
build_config.release = self._is_present("release");
278+
274279
let opts = CompileOptions {
275280
config,
276-
jobs: self.jobs()?,
277-
target: self.target(),
281+
build_config,
278282
features: self._values_of("features"),
279283
all_features: self._is_present("all-features"),
280284
no_default_features: self._is_present("no-default-features"),
281285
spec,
282-
mode,
283-
release: self._is_present("release"),
284286
filter: CompileFilter::new(
285287
self._is_present("lib"),
286288
self._values_of("bin"),
@@ -293,7 +295,6 @@ pub trait ArgMatchesExt {
293295
self._is_present("benches"),
294296
self._is_present("all-targets"),
295297
),
296-
message_format,
297298
target_rustdoc_args: None,
298299
target_rustc_args: None,
299300
export_dir: None,

src/bin/cargo/commands/bench.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode, TestOptions};
3+
use cargo::ops::{self, TestOptions};
44

55
pub fn cli() -> App {
66
subcommand("bench")
@@ -73,7 +73,7 @@ Compilation can be customized with the `bench` profile in the manifest.
7373
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
7474
let ws = args.workspace(config)?;
7575
let mut compile_opts = args.compile_options(config, CompileMode::Bench)?;
76-
compile_opts.release = true;
76+
compile_opts.build_config.release = true;
7777

7878
let ops = TestOptions {
7979
no_run: args.is_present("no-run"),

src/bin/cargo/commands/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode};
3+
use cargo::ops;
44

55
pub fn cli() -> App {
66
subcommand("build")

src/bin/cargo/commands/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode};
3+
use cargo::ops;
44

55
pub fn cli() -> App {
66
subcommand("check")

src/bin/cargo/commands/doc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode, DocOptions};
3+
use cargo::ops::{self, DocOptions};
44

55
pub fn cli() -> App {
66
subcommand("doc")

src/bin/cargo/commands/install.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use command_prelude::*;
22

33
use cargo::core::{GitReference, SourceId};
4-
use cargo::ops::{self, CompileMode};
4+
use cargo::ops;
55
use cargo::util::ToUrl;
66

77
pub fn cli() -> App {
@@ -73,7 +73,7 @@ continuous integration systems.",
7373

7474
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
7575
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
76-
compile_opts.release = !args.is_present("debug");
76+
compile_opts.build_config.release = !args.is_present("debug");
7777

7878
let krates = args.values_of("crate")
7979
.unwrap_or_default()

src/bin/cargo/commands/run.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use command_prelude::*;
22

33
use cargo::core::Verbosity;
4-
use cargo::ops::{self, CompileFilter, CompileMode};
4+
use cargo::ops::{self, CompileFilter};
55

66
pub fn cli() -> App {
77
subcommand("run")

src/bin/cargo/commands/rustc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode};
3+
use cargo::ops;
44

55
pub fn cli() -> App {
66
subcommand("rustc")

src/bin/cargo/commands/rustdoc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode, DocOptions};
3+
use cargo::ops::{self, DocOptions};
44

55
pub fn cli() -> App {
66
subcommand("rustdoc")

src/bin/cargo/commands/test.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use command_prelude::*;
22

3-
use cargo::ops::{self, CompileMode};
3+
use cargo::ops;
44

55
pub fn cli() -> App {
66
subcommand("test")
@@ -94,7 +94,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
9494
let mut compile_opts = args.compile_options(config, CompileMode::Test)?;
9595
let doc = args.is_present("doc");
9696
if doc {
97-
compile_opts.mode = ops::CompileMode::Doctest;
97+
compile_opts.build_config.mode = CompileMode::Doctest;
9898
compile_opts.filter = ops::CompileFilter::new(
9999
true,
100100
Vec::new(),
+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
use std::path::Path;
2+
use util::{CargoResult, CargoResultExt, Config};
3+
4+
/// Configuration information for a rustc build.
5+
#[derive(Debug)]
6+
pub struct BuildConfig {
7+
/// The target arch triple, defaults to host arch
8+
pub requested_target: Option<String>,
9+
/// How many rustc jobs to run in parallel
10+
pub jobs: u32,
11+
/// Whether we are building for release
12+
pub release: bool,
13+
/// In what mode we are compiling
14+
pub mode: CompileMode,
15+
/// Whether to print std output in json format (for machine reading)
16+
pub message_format: MessageFormat,
17+
}
18+
19+
impl BuildConfig {
20+
/// Parse all config files to learn about build configuration. Currently
21+
/// configured options are:
22+
///
23+
/// * build.jobs
24+
/// * build.target
25+
/// * target.$target.ar
26+
/// * target.$target.linker
27+
/// * target.$target.libfoo.metadata
28+
pub fn new(
29+
config: &Config,
30+
jobs: Option<u32>,
31+
requested_target: &Option<String>,
32+
mode: CompileMode,
33+
) -> CargoResult<BuildConfig> {
34+
let requested_target = match requested_target {
35+
&Some(ref target) if target.ends_with(".json") => {
36+
let path = Path::new(target)
37+
.canonicalize()
38+
.chain_err(|| format_err!("Target path {:?} is not a valid file", target))?;
39+
Some(path.into_os_string()
40+
.into_string()
41+
.map_err(|_| format_err!("Target path is not valid unicode"))?)
42+
}
43+
other => other.clone(),
44+
};
45+
if let Some(ref s) = requested_target {
46+
if s.trim().is_empty() {
47+
bail!("target was empty")
48+
}
49+
}
50+
let cfg_target = config.get_string("build.target")?.map(|s| s.val);
51+
let target = requested_target.clone().or(cfg_target);
52+
53+
if jobs == Some(0) {
54+
bail!("jobs must be at least 1")
55+
}
56+
if jobs.is_some() && config.jobserver_from_env().is_some() {
57+
config.shell().warn(
58+
"a `-j` argument was passed to Cargo but Cargo is \
59+
also configured with an external jobserver in \
60+
its environment, ignoring the `-j` parameter",
61+
)?;
62+
}
63+
let cfg_jobs = match config.get_i64("build.jobs")? {
64+
Some(v) => {
65+
if v.val <= 0 {
66+
bail!(
67+
"build.jobs must be positive, but found {} in {}",
68+
v.val,
69+
v.definition
70+
)
71+
} else if v.val >= i64::from(u32::max_value()) {
72+
bail!(
73+
"build.jobs is too large: found {} in {}",
74+
v.val,
75+
v.definition
76+
)
77+
} else {
78+
Some(v.val as u32)
79+
}
80+
}
81+
None => None,
82+
};
83+
let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32);
84+
Ok(BuildConfig {
85+
requested_target: target,
86+
jobs,
87+
release: false,
88+
mode,
89+
message_format: MessageFormat::Human,
90+
})
91+
}
92+
93+
pub fn json_messages(&self) -> bool {
94+
self.message_format == MessageFormat::Json
95+
}
96+
97+
pub fn test(&self) -> bool {
98+
self.mode == CompileMode::Test || self.mode == CompileMode::Bench
99+
}
100+
}
101+
102+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
103+
pub enum MessageFormat {
104+
Human,
105+
Json,
106+
}
107+
108+
/// The general "mode" of what to do.
109+
/// This is used for two purposes. The commands themselves pass this in to
110+
/// `compile_ws` to tell it the general execution strategy. This influences
111+
/// the default targets selected. The other use is in the `Unit` struct
112+
/// to indicate what is being done with a specific target.
113+
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash)]
114+
pub enum CompileMode {
115+
/// A target being built for a test.
116+
Test,
117+
/// Building a target with `rustc` (lib or bin).
118+
Build,
119+
/// Building a target with `rustc` to emit `rmeta` metadata only. If
120+
/// `test` is true, then it is also compiled with `--test` to check it like
121+
/// a test.
122+
Check { test: bool },
123+
/// Used to indicate benchmarks should be built. This is not used in
124+
/// `Target` because it is essentially the same as `Test` (indicating
125+
/// `--test` should be passed to rustc) and by using `Test` instead it
126+
/// allows some de-duping of Units to occur.
127+
Bench,
128+
/// A target that will be documented with `rustdoc`.
129+
/// If `deps` is true, then it will also document all dependencies.
130+
Doc { deps: bool },
131+
/// A target that will be tested with `rustdoc`.
132+
Doctest,
133+
/// A marker for Units that represent the execution of a `build.rs`
134+
/// script.
135+
RunCustomBuild,
136+
}
137+
138+
impl CompileMode {
139+
/// Returns true if the unit is being checked.
140+
pub fn is_check(&self) -> bool {
141+
match *self {
142+
CompileMode::Check { .. } => true,
143+
_ => false,
144+
}
145+
}
146+
147+
/// Returns true if this is a doc or doctest. Be careful using this.
148+
/// Although both run rustdoc, the dependencies for those two modes are
149+
/// very different.
150+
pub fn is_doc(&self) -> bool {
151+
match *self {
152+
CompileMode::Doc { .. } | CompileMode::Doctest => true,
153+
_ => false,
154+
}
155+
}
156+
157+
/// Returns true if this is any type of test (test, benchmark, doctest, or
158+
/// check-test).
159+
pub fn is_any_test(&self) -> bool {
160+
match *self {
161+
CompileMode::Test
162+
| CompileMode::Bench
163+
| CompileMode::Check { test: true }
164+
| CompileMode::Doctest => true,
165+
_ => false,
166+
}
167+
}
168+
169+
/// Returns true if this is the *execution* of a `build.rs` script.
170+
pub fn is_run_custom_build(&self) -> bool {
171+
*self == CompileMode::RunCustomBuild
172+
}
173+
174+
/// List of all modes (currently used by `cargo clean -p` for computing
175+
/// all possible outputs).
176+
pub fn all_modes() -> &'static [CompileMode] {
177+
static ALL: [CompileMode; 9] = [
178+
CompileMode::Test,
179+
CompileMode::Build,
180+
CompileMode::Check { test: true },
181+
CompileMode::Check { test: false },
182+
CompileMode::Bench,
183+
CompileMode::Doc { deps: true },
184+
CompileMode::Doc { deps: false },
185+
CompileMode::Doctest,
186+
CompileMode::RunCustomBuild,
187+
];
188+
&ALL
189+
}
190+
}

0 commit comments

Comments
 (0)