]> git.proxmox.com Git - cargo.git/blame - src/cargo/ops/cargo_compile.rs
Auto merge of #4340 - debris:fixed_4310, r=alexcrichton
[cargo.git] / src / cargo / ops / cargo_compile.rs
CommitLineData
64ff29ff
AC
1//!
2//! Cargo compile currently does the following steps:
3//!
4//! All configurations are already injected as environment variables via the
5//! main cargo command
6//!
7//! 1. Read the manifest
8//! 2. Shell out to `cargo-resolve` with a list of dependencies and sources as
9//! stdin
10//!
11//! a. Shell out to `--do update` and `--do list` for each source
12//! b. Resolve dependencies and return a list of name/version/source
13//!
14//! 3. Shell out to `--do download` for each source
15//! 4. Shell out to `--do get` for each source, and build up the list of paths
16//! to pass to rustc -L
17//! 5. Call `cargo-rustc` with the results of the resolver zipped together with
18//! the results of the `get`
19//!
20//! a. Topologically sort the dependencies
21//! b. Compile each dependency in order, passing in the -L's pointing at each
22//! previously compiled dependency
23//!
62bff631 24
f3468348
JB
25use std::collections::{HashMap, HashSet};
26use std::default::Default;
58ddb28a 27use std::path::PathBuf;
1ab19a5a 28use std::sync::Arc;
12af54e1 29
f00e8901 30use core::{Source, Package, Target};
e21bb08f
JB
31use core::{Profile, TargetKind, Profiles, Workspace, PackageId, PackageIdSpec};
32use core::resolver::Resolve;
8c3b3605 33use ops::{self, BuildOutput, Executor, DefaultExecutor};
56db20df 34use util::config::Config;
f00e8901 35use util::{CargoResult, profile};
50f110a4 36
bacb6be3 37/// Contains information about how a package should be compiled.
2fe0bf83
AC
38pub struct CompileOptions<'a> {
39 pub config: &'a Config,
c7641c24 40 /// Number of concurrent jobs to use.
55321111 41 pub jobs: Option<u32>,
c7641c24 42 /// The target platform to compile for (example: `i686-unknown-linux-gnu`).
1946c447 43 pub target: Option<&'a str>,
9e779198 44 /// Extra features to build for the root package
2b46d039 45 pub features: &'a [String],
1f8b3988
DA
46 /// Flag whether all available features should be built for the root package
47 pub all_features: bool,
9e779198 48 /// Flag if the default feature should be built for the root package
2b46d039 49 pub no_default_features: bool,
6b32c4d7 50 /// A set of packages to build.
62c04979 51 pub spec: Packages<'a>,
9e779198
AC
52 /// Filter to apply to the root package to select which targets will be
53 /// built.
54 pub filter: CompileFilter<'a>,
9e779198
AC
55 /// Whether this is a release build or not
56 pub release: bool,
57 /// Mode for this compile.
58 pub mode: CompileMode,
9f98208d
AK
59 /// `--error_format` flag for the compiler.
60 pub message_format: MessageFormat,
4816a2a5 61 /// Extra arguments to be passed to rustdoc (for main crate and dependencies)
54127ce8 62 pub target_rustdoc_args: Option<&'a [String]>,
77bb01ec
SL
63 /// The specified target will be compiled with all the available arguments,
64 /// note that this only accounts for the *final* invocation of rustc
65 pub target_rustc_args: Option<&'a [String]>,
9e779198
AC
66}
67
69caa63b 68impl<'a> CompileOptions<'a> {
1ab19a5a 69 pub fn default(config: &'a Config, mode: CompileMode) -> CompileOptions<'a>
69caa63b 70 {
1ab19a5a 71 CompileOptions {
69caa63b
NC
72 config: config,
73 jobs: None,
74 target: None,
75 features: &[],
76 all_features: false,
77 no_default_features: false,
78 spec: ops::Packages::Packages(&[]),
79 mode: mode,
80 release: false,
2a82378a 81 filter: CompileFilter::Everything { required_features_filterable: false },
69caa63b
NC
82 message_format: MessageFormat::Human,
83 target_rustdoc_args: None,
84 target_rustc_args: None,
1ab19a5a 85 }
69caa63b
NC
86 }
87}
88
856641cc 89#[derive(Clone, Copy, PartialEq, Debug)]
9e779198
AC
90pub enum CompileMode {
91 Test,
92 Build,
4b82fdc0 93 Check,
9e779198 94 Bench,
8350cd17 95 Doc { deps: bool },
fb1736ef 96 Doctest,
9e779198
AC
97}
98
10373f40 99#[derive(Clone, Copy, PartialEq, Eq, Deserialize)]
9f98208d
AK
100pub enum MessageFormat {
101 Human,
102 Json
103}
104
261ae46f 105#[derive(Clone, Copy, PartialEq, Eq, Debug)]
62c04979
AR
106pub enum Packages<'a> {
107 All,
1f57e2ca 108 OptOut(&'a [String]),
62c04979
AR
109 Packages(&'a [String]),
110}
111
6b32c4d7 112impl<'a> Packages<'a> {
33431d71 113 pub fn from_flags(virtual_ws: bool, all: bool, exclude: &'a Vec<String>, package: &'a Vec<String>)
7ffd1cfc 114 -> CargoResult<Self>
115 {
33431d71 116 let all = all || (virtual_ws && package.is_empty());
117
7ffd1cfc 118 let packages = match (all, &exclude) {
119 (true, exclude) if exclude.is_empty() => Packages::All,
120 (true, exclude) => Packages::OptOut(exclude),
121 (false, exclude) if !exclude.is_empty() => bail!("--exclude can only be used together \
122 with --all"),
123 _ => Packages::Packages(package),
124 };
125
126 Ok(packages)
127 }
128
6b32c4d7
AK
129 pub fn into_package_id_specs(self, ws: &Workspace) -> CargoResult<Vec<PackageIdSpec>> {
130 let specs = match self {
131 Packages::All => {
132 ws.members()
133 .map(Package::package_id)
134 .map(PackageIdSpec::from_package_id)
135 .collect()
136 }
1f57e2ca 137 Packages::OptOut(opt_out) => {
138 ws.members()
139 .map(Package::package_id)
140 .map(PackageIdSpec::from_package_id)
141 .filter(|p| opt_out.iter().position(|x| *x == p.name()).is_none())
142 .collect()
143 }
6b32c4d7
AK
144 Packages::Packages(packages) => {
145 packages.iter().map(|p| PackageIdSpec::parse(&p)).collect::<CargoResult<Vec<_>>>()?
146 }
147 };
148 Ok(specs)
149 }
150}
151
2a82378a
BW
152#[derive(Clone, Copy)]
153pub enum FilterRule<'a> {
154 All,
155 Just (&'a [String]),
156}
157
9e779198 158pub enum CompileFilter<'a> {
25e50b58
JB
159 Everything {
160 /// Flag whether targets can be safely skipped when required-features are not satisfied.
161 required_features_filterable: bool,
162 },
9e779198
AC
163 Only {
164 lib: bool,
2a82378a
BW
165 bins: FilterRule<'a>,
166 examples: FilterRule<'a>,
167 tests: FilterRule<'a>,
168 benches: FilterRule<'a>,
9e779198 169 }
a1980dc7
YKCL
170}
171
58ddb28a 172pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions<'a>)
8a8ea1e8 173 -> CargoResult<ops::Compilation<'a>> {
1ab19a5a 174 compile_with_exec(ws, options, Arc::new(DefaultExecutor))
8c3b3605
NC
175}
176
1ab19a5a 177pub fn compile_with_exec<'a>(ws: &Workspace<'a>,
261ae46f 178 options: &CompileOptions<'a>,
1ab19a5a
NC
179 exec: Arc<Executor>)
180 -> CargoResult<ops::Compilation<'a>> {
81e5c764
AR
181 for member in ws.members() {
182 for key in member.manifest().warnings().iter() {
62c04979
AR
183 options.config.shell().warn(key)?
184 }
9fba127e 185 }
8c3b3605 186 compile_ws(ws, None, options, exec)
9fba127e
AC
187}
188
1ab19a5a
NC
189pub fn compile_ws<'a>(ws: &Workspace<'a>,
190 source: Option<Box<Source + 'a>>,
191 options: &CompileOptions<'a>,
192 exec: Arc<Executor>)
193 -> CargoResult<ops::Compilation<'a>> {
f0647ea2 194 let CompileOptions { config, jobs, target, spec, features,
1f8b3988 195 all_features, no_default_features,
9f98208d 196 release, mode, message_format,
9f6a8a78 197 ref filter,
54127ce8 198 ref target_rustdoc_args,
77bb01ec 199 ref target_rustc_args } = *options;
3656bec8 200
9fba127e 201 let target = target.map(|s| s.to_string());
9fba127e 202
5d0cb3f2 203 if jobs == Some(0) {
7ab18e3a 204 bail!("jobs must be at least 1")
5d0cb3f2 205 }
a2aa2bf9 206
151f12fc 207 let profiles = ws.profiles();
a9562433 208
6b32c4d7 209 let specs = spec.into_package_id_specs(ws)?;
c7211de3 210 let resolve = ops::resolve_ws_precisely(ws,
f00e8901
AK
211 source,
212 features,
213 all_features,
214 no_default_features,
215 &specs)?;
6b32c4d7 216 let (packages, resolve_with_overrides) = resolve;
9c296792 217
ab9f64dd 218 let mut pkgids = Vec::new();
6b32c4d7
AK
219 if specs.len() > 0 {
220 for p in specs.iter() {
1e0c29c2 221 pkgids.push(p.query(resolve_with_overrides.iter())?);
ab9f64dd 222 }
b3ade7c7 223 } else {
62c04979 224 let root_package = ws.current()?;
0002d440
JB
225 let all_features = resolve_all_features(&resolve_with_overrides,
226 root_package.package_id());
e21bb08f 227 generate_targets(root_package, profiles, mode, filter, &all_features, release)?;
ab9f64dd 228 pkgids.push(root_package.package_id());
69bc3d05 229 };
b3ade7c7 230
82655b46 231 let to_builds = pkgids.iter().map(|id| {
b56b61c5 232 packages.get(id)
82655b46 233 }).collect::<CargoResult<Vec<_>>>()?;
f0647ea2
FH
234
235 let mut general_targets = Vec::new();
236 let mut package_targets = Vec::new();
237
54127ce8
AC
238 match (*target_rustc_args, *target_rustdoc_args) {
239 (Some(..), _) |
240 (_, Some(..)) if to_builds.len() != 1 => {
241 panic!("`rustc` and `rustdoc` should not accept multiple `-p` flags")
242 }
243 (Some(args), _) => {
0002d440
JB
244 let all_features = resolve_all_features(&resolve_with_overrides,
245 to_builds[0].package_id());
82655b46 246 let targets = generate_targets(to_builds[0], profiles,
e21bb08f 247 mode, filter, &all_features, release)?;
54127ce8
AC
248 if targets.len() == 1 {
249 let (target, profile) = targets[0];
250 let mut profile = profile.clone();
251 profile.rustc_args = Some(args.to_vec());
252 general_targets.push((target, profile));
253 } else {
7ab18e3a
AC
254 bail!("extra arguments to `rustc` can only be passed to one \
255 target, consider filtering\nthe package by passing \
256 e.g. `--lib` or `--bin NAME` to specify a single target")
54127ce8
AC
257 }
258 }
259 (None, Some(args)) => {
0002d440
JB
260 let all_features = resolve_all_features(&resolve_with_overrides,
261 to_builds[0].package_id());
82655b46 262 let targets = generate_targets(to_builds[0], profiles,
e21bb08f 263 mode, filter, &all_features, release)?;
54127ce8
AC
264 if targets.len() == 1 {
265 let (target, profile) = targets[0];
266 let mut profile = profile.clone();
267 profile.rustdoc_args = Some(args.to_vec());
268 general_targets.push((target, profile));
f0647ea2 269 } else {
7ab18e3a
AC
270 bail!("extra arguments to `rustdoc` can only be passed to one \
271 target, consider filtering\nthe package by passing e.g. \
272 `--lib` or `--bin NAME` to specify a single target")
b3ade7c7 273 }
f0647ea2 274 }
54127ce8 275 (None, None) => {
f0647ea2 276 for &to_build in to_builds.iter() {
0002d440
JB
277 let all_features = resolve_all_features(&resolve_with_overrides,
278 to_build.package_id());
82655b46 279 let targets = generate_targets(to_build, profiles, mode,
e21bb08f 280 filter, &all_features, release)?;
f0647ea2 281 package_targets.push((to_build, targets));
b3ade7c7 282 }
f0647ea2
FH
283 }
284 };
b3ade7c7 285
f0647ea2 286 for &(target, ref profile) in &general_targets {
b3ade7c7
FH
287 for &to_build in to_builds.iter() {
288 package_targets.push((to_build, vec![(target, profile)]));
8a8ea1e8 289 }
b3ade7c7 290 }
582e9d94 291
b3ade7c7 292 let mut ret = {
4f12a2b5 293 let _p = profile::start("compiling");
82655b46 294 let mut build_config = scrape_build_config(config, jobs, target)?;
9e779198 295 build_config.release = release;
0f44202b 296 build_config.test = mode == CompileMode::Test || mode == CompileMode::Bench;
9f6d7989 297 build_config.json_messages = message_format == MessageFormat::Json;
8350cd17
AC
298 if let CompileMode::Doc { deps } = mode {
299 build_config.doc_all = deps;
300 }
e1434913 301
82655b46 302 ops::compile_targets(ws,
9c7ef529
SG
303 &package_targets,
304 &packages,
305 &resolve_with_overrides,
306 config,
307 build_config,
8c3b3605
NC
308 profiles,
309 exec)?
0484cd88 310 };
8b840393 311
b3ade7c7
FH
312 ret.to_doc_test = to_builds.iter().map(|&p| p.clone()).collect();
313
e21bb08f
JB
314 return Ok(ret);
315
316 fn resolve_all_features(resolve_with_overrides: &Resolve,
317 package_id: &PackageId)
318 -> HashSet<String> {
50f1c172 319 let mut features = resolve_with_overrides.features(package_id).clone();
e21bb08f
JB
320
321 // Include features enabled for use by dependencies so targets can also use them with the
322 // required-features field when deciding whether to be built or skipped.
323 let deps = resolve_with_overrides.deps(package_id);
324 for dep in deps {
50f1c172
AK
325 for feature in resolve_with_overrides.features(dep) {
326 features.insert(dep.name().to_string() + "/" + feature);
e21bb08f
JB
327 }
328 }
329
330 features
331 }
62bff631 332}
51c9cf0f 333
2a82378a
BW
334impl<'a> FilterRule<'a> {
335 pub fn new(targets: &'a [String], all: bool) -> FilterRule<'a> {
336 if all {
337 FilterRule::All
338 } else {
339 FilterRule::Just(targets)
340 }
341 }
342
343 fn matches(&self, target: &Target) -> bool {
344 match *self {
345 FilterRule::All => true,
346 FilterRule::Just(targets) => {
347 targets.iter().any(|x| *x == target.name())
348 },
349 }
350 }
351
352 fn is_specific(&self) -> bool {
353 match *self {
354 FilterRule::All => true,
355 FilterRule::Just(targets) => !targets.is_empty(),
356 }
357 }
358
359 pub fn try_collect(&self) -> Option<Vec<String>> {
360 match *self {
361 FilterRule::All => None,
362 FilterRule::Just(targets) => Some(targets.iter().map(|t| t.clone()).collect()),
363 }
364 }
365}
366
9e779198 367impl<'a> CompileFilter<'a> {
7a1d8d94 368 pub fn new(lib_only: bool,
2a82378a
BW
369 bins: &'a [String], all_bins: bool,
370 tsts: &'a [String], all_tsts: bool,
371 exms: &'a [String], all_exms: bool,
372 bens: &'a [String], all_bens: bool) -> CompileFilter<'a> {
373 let rule_bins = FilterRule::new(bins, all_bins);
374 let rule_tsts = FilterRule::new(tsts, all_tsts);
375 let rule_exms = FilterRule::new(exms, all_exms);
376 let rule_bens = FilterRule::new(bens, all_bens);
377
378 if lib_only || rule_bins.is_specific() || rule_tsts.is_specific()
379 || rule_exms.is_specific() || rule_bens.is_specific() {
7a1d8d94 380 CompileFilter::Only {
2a82378a
BW
381 lib: lib_only, bins: rule_bins,
382 examples: rule_exms, benches: rule_bens,
383 tests: rule_tsts,
7a1d8d94
AC
384 }
385 } else {
25e50b58
JB
386 CompileFilter::Everything {
387 required_features_filterable: true,
388 }
7a1d8d94
AC
389 }
390 }
391
9e779198
AC
392 pub fn matches(&self, target: &Target) -> bool {
393 match *self {
25e50b58 394 CompileFilter::Everything { .. } => true,
9e779198 395 CompileFilter::Only { lib, bins, examples, tests, benches } => {
2a82378a 396 let rule = match *target.kind() {
9e779198
AC
397 TargetKind::Bin => bins,
398 TargetKind::Test => tests,
399 TargetKind::Bench => benches,
47b25fd3
KA
400 TargetKind::ExampleBin |
401 TargetKind::ExampleLib(..) => examples,
9e779198
AC
402 TargetKind::Lib(..) => return lib,
403 TargetKind::CustomBuild => return false,
404 };
2a82378a 405 rule.matches(target)
9e779198
AC
406 }
407 }
408 }
c98b8c4c
BW
409
410 pub fn is_specific(&self) -> bool {
411 match *self {
412 CompileFilter::Everything { .. } => false,
413 CompileFilter::Only { .. } => true,
414 }
415 }
9e779198
AC
416}
417
2a82378a
BW
418#[derive(Clone, Copy, Debug)]
419struct BuildProposal<'a> {
420 target: &'a Target,
421 profile: &'a Profile,
422 required: bool,
423}
424
425fn generate_auto_targets<'a>(mode: CompileMode, targets: &'a [Target],
426 profile: &'a Profile,
427 dep: &'a Profile,
428 required_features_filterable: bool) -> Vec<BuildProposal<'a>> {
429 match mode {
430 CompileMode::Bench => {
431 targets.iter().filter(|t| t.benched()).map(|t| {
432 BuildProposal {
433 target: t,
434 profile: profile,
435 required: !required_features_filterable,
436 }
437 }).collect::<Vec<_>>()
438 }
439 CompileMode::Test => {
440 let mut base = targets.iter().filter(|t| {
441 t.tested()
442 }).map(|t| {
443 BuildProposal {
444 target: t,
445 profile: if t.is_example() {dep} else {profile},
446 required: !required_features_filterable,
447 }
448 }).collect::<Vec<_>>();
449
450 // Always compile the library if we're testing everything as
451 // it'll be needed for doctests
452 if let Some(t) = targets.iter().find(|t| t.is_lib()) {
453 if t.doctested() {
454 base.push(BuildProposal {
455 target: t,
456 profile: dep,
457 required: !required_features_filterable,
458 });
459 }
460 }
461 base
462 }
463 CompileMode::Build | CompileMode::Check => {
464 targets.iter().filter(|t| {
465 t.is_bin() || t.is_lib()
466 }).map(|t| BuildProposal {
467 target: t,
468 profile: profile,
469 required: !required_features_filterable,
470 }).collect()
471 }
472 CompileMode::Doc { .. } => {
473 targets.iter().filter(|t| {
474 t.documented()
475 }).map(|t| BuildProposal {
476 target: t,
477 profile: profile,
478 required: !required_features_filterable,
479 }).collect()
480 }
481 CompileMode::Doctest => {
482 if let Some(t) = targets.iter().find(|t| t.is_lib()) {
483 if t.doctested() {
484 return vec![BuildProposal {
485 target: t,
486 profile: profile,
487 required: !required_features_filterable,
488 }];
489 }
490 }
491
492 Vec::new()
493 }
494 }
495}
496
497/// Given a filter rule and some context, propose a list of targets
498fn propose_indicated_targets<'a>(pkg: &'a Package,
499 rule: FilterRule,
500 desc: &'static str,
501 is_expected_kind: fn(&Target) -> bool,
502 profile: &'a Profile) -> CargoResult<Vec<BuildProposal<'a>>> {
503 match rule {
504 FilterRule::All => {
505 let result = pkg.targets().iter().filter(|t| is_expected_kind(t)).map(|t| {
506 BuildProposal {
507 target: t,
508 profile: profile,
509 required: false,
510 }
511 });
512 return Ok(result.collect());
513 }
514 FilterRule::Just(names) => {
515 let mut targets = Vec::new();
516 for name in names {
517 let target = pkg.targets().iter().find(|t| {
518 t.name() == *name && is_expected_kind(t)
519 });
520 let t = match target {
521 Some(t) => t,
522 None => {
523 let suggestion = pkg.find_closest_target(name, is_expected_kind);
524 match suggestion {
525 Some(s) => {
526 let suggested_name = s.name();
527 bail!("no {} target named `{}`\n\nDid you mean `{}`?",
528 desc, name, suggested_name)
529 }
530 None => bail!("no {} target named `{}`", desc, name),
531 }
532 }
533 };
534 debug!("found {} `{}`", desc, name);
535 targets.push(BuildProposal {
536 target: t,
537 profile: profile,
538 required: true,
539 });
540 }
541 return Ok(targets);
542 }
543 }
544}
545
546/// Collect the targets that are libraries or have all required features available.
547fn filter_compatible_targets<'a>(mut proposals: Vec<BuildProposal<'a>>,
548 features: &HashSet<String>)
549 -> CargoResult<Vec<(&'a Target, &'a Profile)>> {
550 let mut compatible = Vec::with_capacity(proposals.len());
551 for proposal in proposals.drain(..) {
552 let unavailable_features = match proposal.target.required_features() {
553 Some(rf) => rf.iter().filter(|f| !features.contains(*f)).collect(),
554 None => Vec::new(),
555 };
556 if proposal.target.is_lib() || unavailable_features.is_empty() {
557 compatible.push((proposal.target, proposal.profile));
558 } else if proposal.required {
559 let required_features = proposal.target.required_features().unwrap();
560 let quoted_required_features: Vec<String> = required_features.iter()
561 .map(|s| format!("`{}`",s))
562 .collect();
563 bail!("target `{}` requires the features: {}\n\
564 Consider enabling them by passing e.g. `--features=\"{}\"`",
565 proposal.target.name(),
566 quoted_required_features.join(", "),
567 required_features.join(" "));
568 }
569 }
570 Ok(compatible)
571}
572
9e779198
AC
573/// Given the configuration for a build, this function will generate all
574/// target/profile combinations needed to be built.
575fn generate_targets<'a>(pkg: &'a Package,
e50ccf73 576 profiles: &'a Profiles,
9e779198
AC
577 mode: CompileMode,
578 filter: &CompileFilter,
e21bb08f 579 features: &HashSet<String>,
9e779198
AC
580 release: bool)
581 -> CargoResult<Vec<(&'a Target, &'a Profile)>> {
9e779198 582 let build = if release {&profiles.release} else {&profiles.dev};
26cf0049 583 let test = if release {&profiles.bench} else {&profiles.test};
9e779198 584 let profile = match mode {
26cf0049 585 CompileMode::Test => test,
9e779198
AC
586 CompileMode::Bench => &profiles.bench,
587 CompileMode::Build => build,
4b82fdc0 588 CompileMode::Check => &profiles.check,
8350cd17 589 CompileMode::Doc { .. } => &profiles.doc,
fb1736ef 590 CompileMode::Doctest => &profiles.doctest,
9e779198 591 };
fb1736ef 592
2a82378a
BW
593 let targets = match *filter {
594 CompileFilter::Everything { required_features_filterable } => {
595 let deps = if release {
596 &profiles.bench_deps
597 } else {
598 &profiles.test_deps
599 };
600 generate_auto_targets(mode, pkg.targets(), profile, deps, required_features_filterable)
9e779198
AC
601 }
602 CompileFilter::Only { lib, bins, examples, tests, benches } => {
603 let mut targets = Vec::new();
604
605 if lib {
606 if let Some(t) = pkg.targets().iter().find(|t| t.is_lib()) {
2a82378a
BW
607 targets.push(BuildProposal {
608 target: t,
609 profile: profile,
610 required: true,
611 });
9e779198 612 } else {
7ab18e3a 613 bail!("no library targets found")
9e779198
AC
614 }
615 }
616
2a82378a
BW
617 targets.append(&mut propose_indicated_targets(
618 pkg, bins, "bin", Target::is_bin, profile)?);
619 targets.append(&mut propose_indicated_targets(
620 pkg, examples, "example", Target::is_example, build)?);
621 targets.append(&mut propose_indicated_targets(
622 pkg, tests, "test", Target::is_test, test)?);
623 targets.append(&mut propose_indicated_targets(
624 pkg, benches, "bench", Target::is_bench, &profiles.bench)?);
f3468348
JB
625 targets
626 }
627 };
628
2a82378a 629 filter_compatible_targets(targets, features)
9e779198
AC
630}
631
9e779198
AC
632/// Parse all config files to learn about build configuration. Currently
633/// configured options are:
634///
635/// * build.jobs
74420506 636/// * build.target
9e779198
AC
637/// * target.$target.ar
638/// * target.$target.linker
639/// * target.$target.libfoo.metadata
ac4eddbb 640fn scrape_build_config(config: &Config,
5d0cb3f2 641 jobs: Option<u32>,
9e779198
AC
642 target: Option<String>)
643 -> CargoResult<ops::BuildConfig> {
cbf25a9b
AC
644 if jobs.is_some() && config.jobserver_from_env().is_some() {
645 config.shell().warn("a `-j` argument was passed to Cargo but Cargo is \
646 also configured with an external jobserver in \
647 its environment, ignoring the `-j` parameter")?;
648 }
82655b46 649 let cfg_jobs = match config.get_i64("build.jobs")? {
455f800c
AC
650 Some(v) => {
651 if v.val <= 0 {
652 bail!("build.jobs must be positive, but found {} in {}",
653 v.val, v.definition)
654 } else if v.val >= u32::max_value() as i64 {
655 bail!("build.jobs is too large: found {} in {}", v.val,
656 v.definition)
80fe0e6d 657 } else {
455f800c 658 Some(v.val as u32)
fa561275
AC
659 }
660 }
661 None => None,
662 };
80fe0e6d 663 let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32);
82655b46 664 let cfg_target = config.get_string("build.target")?.map(|s| s.val);
74420506 665 let target = target.or(cfg_target);
5d0cb3f2 666 let mut base = ops::BuildConfig {
82655b46 667 host_triple: config.rustc()?.host.clone(),
5d0cb3f2 668 requested_target: target.clone(),
d469bbcb 669 jobs: jobs,
5d0cb3f2
AC
670 ..Default::default()
671 };
82655b46 672 base.host = scrape_target_config(config, &base.host_triple)?;
5d0cb3f2 673 base.target = match target.as_ref() {
82655b46 674 Some(triple) => scrape_target_config(config, &triple)?,
5d0cb3f2 675 None => base.host.clone(),
ac4eddbb 676 };
5d0cb3f2 677 Ok(base)
ac4eddbb
AC
678}
679
a468236a 680fn scrape_target_config(config: &Config, triple: &str)
ac4eddbb 681 -> CargoResult<ops::TargetConfig> {
d9190d98 682
a468236a 683 let key = format!("target.{}", triple);
ac4eddbb 684 let mut ret = ops::TargetConfig {
82655b46
SG
685 ar: config.get_path(&format!("{}.ar", key))?.map(|v| v.val),
686 linker: config.get_path(&format!("{}.linker", key))?.map(|v| v.val),
ac4eddbb
AC
687 overrides: HashMap::new(),
688 };
82655b46 689 let table = match config.get_table(&key)? {
455f800c 690 Some(table) => table.val,
a468236a
AC
691 None => return Ok(ret),
692 };
53b74226 693 for (lib_name, value) in table {
e1a85a60
IS
694 match lib_name.as_str() {
695 "ar" | "linker" | "runner" | "rustflags" => {
696 continue
697 },
698 _ => {}
455f800c 699 }
a468236a
AC
700
701 let mut output = BuildOutput {
702 library_paths: Vec::new(),
703 library_links: Vec::new(),
61a0ace4 704 cfgs: Vec::new(),
8b744a05 705 env: Vec::new(),
a468236a 706 metadata: Vec::new(),
7c97c5bf 707 rerun_if_changed: Vec::new(),
fe8bbb7a 708 rerun_if_env_changed: Vec::new(),
a30f612e 709 warnings: Vec::new(),
a468236a 710 };
d38e4d31
NJ
711 // We require deterministic order of evaluation, so we must sort the pairs by key first.
712 let mut pairs = Vec::new();
82655b46 713 for (k, value) in value.table(&lib_name)?.0 {
d38e4d31
NJ
714 pairs.push((k,value));
715 }
716 pairs.sort_by_key( |p| p.0 );
717 for (k,value) in pairs{
a468236a 718 let key = format!("{}.{}", key, k);
56db20df
AC
719 match &k[..] {
720 "rustc-flags" => {
82655b46 721 let (flags, definition) = value.string(&k)?;
56db20df 722 let whence = format!("in `{}` (in {})", key,
53b74226 723 definition.display());
9f6d7989 724 let (paths, links) =
53b74226 725 BuildOutput::parse_rustc_flags(&flags, &whence)
82655b46 726 ?;
53b74226
AC
727 output.library_paths.extend(paths);
728 output.library_links.extend(links);
56db20df
AC
729 }
730 "rustc-link-lib" => {
82655b46 731 let list = value.list(&k)?;
53b74226
AC
732 output.library_links.extend(list.iter()
733 .map(|v| v.0.clone()));
56db20df
AC
734 }
735 "rustc-link-search" => {
82655b46 736 let list = value.list(&k)?;
53b74226 737 output.library_paths.extend(list.iter().map(|v| {
56db20df
AC
738 PathBuf::from(&v.0)
739 }));
740 }
741 "rustc-cfg" => {
82655b46 742 let list = value.list(&k)?;
53b74226 743 output.cfgs.extend(list.iter().map(|v| v.0.clone()));
56db20df 744 }
f1ae9f84
KK
745 "rustc-env" => {
746 for (name, val) in value.table(&k)?.0 {
747 let val = val.string(name)?.0;
748 output.env.push((name.clone(), val.to_string()));
749 }
750 }
fe8bbb7a
AC
751 "warning" |
752 "rerun-if-changed" |
753 "rerun-if-env-changed" => {
8a286df9
VP
754 bail!("`{}` is not supported in build script overrides", k);
755 }
56db20df 756 _ => {
82655b46 757 let val = value.string(&k)?.0;
53b74226 758 output.metadata.push((k.clone(), val.to_string()));
56db20df 759 }
63915360 760 }
12af54e1 761 }
a468236a 762 ret.overrides.insert(lib_name, output);
12af54e1
AC
763 }
764
63915360 765 Ok(ret)
5569835e 766}