]> git.proxmox.com Git - cargo.git/blame - src/cargo/ops/cargo_rustc/context.rs
More lint cleaning
[cargo.git] / src / cargo / ops / cargo_rustc / context.rs
CommitLineData
0cc39aae
AC
1#![allow(deprecated)]
2
3f7b09cc 3use std::collections::{HashSet, HashMap, BTreeSet};
4cfaf9a5 4use std::collections::hash_map::Entry;
e17933ec 5use std::env;
0cc39aae
AC
6use std::fmt;
7use std::hash::{Hasher, Hash, SipHasher};
5a04a4d4 8use std::path::{Path, PathBuf};
f5d786e0 9use std::str::{self, FromStr};
800d9eb8 10use std::sync::Arc;
4cfaf9a5 11use std::cell::RefCell;
1e1412fd 12
cbf25a9b
AC
13use jobserver::Client;
14
2d25fcac 15use core::{Package, PackageId, PackageSet, Resolve, Target, Profile};
0cc39aae 16use core::{TargetKind, Profiles, Dependency, Workspace};
b43d2869 17use core::dependency::Kind as DepKind;
4cfaf9a5 18use util::{self, ProcessBuilder, internal, Config, profile, Cfg, CfgExpr};
e95044e3 19use util::errors::{CargoResult, CargoResultExt};
1e1412fd 20
ac4eddbb 21use super::TargetConfig;
fe8bbb7a 22use super::custom_build::{BuildState, BuildScripts, BuildDeps};
a40d3b03 23use super::fingerprint::Fingerprint;
41579bad 24use super::layout::Layout;
5ea7a97d 25use super::links::Links;
a40d3b03 26use super::{Kind, Compilation, BuildConfig};
9f5d9b81 27
d2ca374c 28#[derive(Clone, Copy, Eq, PartialEq, Hash)]
659f8244
AC
29pub struct Unit<'a> {
30 pub pkg: &'a Package,
31 pub target: &'a Target,
32 pub profile: &'a Profile,
33 pub kind: Kind,
ff19a482
AC
34}
35
8a8ea1e8 36pub struct Context<'a, 'cfg: 'a> {
0ae3a2b4 37 pub ws: &'a Workspace<'cfg>,
8a8ea1e8 38 pub config: &'cfg Config,
f6d22b64 39 pub resolve: &'a Resolve,
8a8ea1e8 40 pub compilation: Compilation<'cfg>,
2d25fcac 41 pub packages: &'a PackageSet<'cfg>,
800d9eb8 42 pub build_state: Arc<BuildState>,
f90d21f6 43 pub build_script_overridden: HashSet<(PackageId, Kind)>,
fe8bbb7a 44 pub build_explicit_deps: HashMap<Unit<'a>, BuildDeps>,
c447e9d0 45 pub fingerprints: HashMap<Unit<'a>, Arc<Fingerprint>>,
659f8244 46 pub compiled: HashSet<Unit<'a>>,
9e779198 47 pub build_config: BuildConfig,
659f8244 48 pub build_scripts: HashMap<Unit<'a>, Arc<BuildScripts>>,
5ea7a97d 49 pub links: Links<'a>,
e9c6b0a0 50 pub used_in_plugin: HashSet<Unit<'a>>,
cbf25a9b 51 pub jobserver: Client,
1e1412fd 52
9f5d9b81
AC
53 host: Layout,
54 target: Option<Layout>,
f5d786e0
AC
55 target_info: TargetInfo,
56 host_info: TargetInfo,
9e779198 57 profiles: &'a Profiles,
a5bf3b88 58 incremental_enabled: bool,
67b3b444 59
e6649dfa 60 target_filenames: HashMap<Unit<'a>, Arc<Vec<(PathBuf, Option<PathBuf>, bool)>>>,
67b3b444 61 target_metadatas: HashMap<Unit<'a>, Option<Metadata>>,
1e1412fd
AC
62}
63
3f7b09cc 64#[derive(Clone, Default)]
f5d786e0 65struct TargetInfo {
4cfaf9a5
MS
66 crate_type_process: Option<ProcessBuilder>,
67 crate_types: RefCell<HashMap<String, Option<(String, String)>>>,
f5d786e0
AC
68 cfg: Option<Vec<Cfg>>,
69}
70
4cfaf9a5
MS
71impl TargetInfo {
72 fn discover_crate_type(&self, crate_type: &str) -> CargoResult<Option<(String, String)>> {
73 let mut process = self.crate_type_process.clone().unwrap();
74
75 process.arg("--crate-type").arg(crate_type);
76
77 let output = process.exec_with_output().chain_err(|| {
78 format!("failed to run `rustc` to learn about \
79 crate-type {} information", crate_type)
80 })?;
81
82 let error = str::from_utf8(&output.stderr).unwrap();
83 let output = str::from_utf8(&output.stdout).unwrap();
84 Ok(parse_crate_type(crate_type, error, &mut output.lines())?)
85 }
86}
87
46a5fe9a 88#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
0cc39aae
AC
89pub struct Metadata(u64);
90
8a8ea1e8 91impl<'a, 'cfg> Context<'a, 'cfg> {
0ae3a2b4 92 pub fn new(ws: &'a Workspace<'cfg>,
77720032 93 resolve: &'a Resolve,
2d25fcac 94 packages: &'a PackageSet<'cfg>,
8a8ea1e8 95 config: &'cfg Config,
9e779198 96 build_config: BuildConfig,
8a8ea1e8 97 profiles: &'a Profiles) -> CargoResult<Context<'a, 'cfg>> {
77720032
AK
98
99 let dest = if build_config.release { "release" } else { "debug" };
23591fe5 100 let host_layout = Layout::new(ws, None, dest)?;
77720032 101 let target_layout = match build_config.requested_target.as_ref() {
23591fe5 102 Some(target) => Some(Layout::new(ws, Some(target), dest)?),
77720032
AK
103 None => None,
104 };
105
a5bf3b88
NM
106 // Enable incremental builds if the user opts in. For now,
107 // this is an environment variable until things stabilize a
108 // bit more.
74cb8636
MS
109 let incremental_enabled = match env::var("CARGO_INCREMENTAL") {
110 Ok(v) => v == "1",
111 Err(_) => false,
112 };
a5bf3b88 113
357bb2de
JG
114 // -Z can only be used on nightly builds; other builds complain loudly.
115 // Since incremental builds only work on nightly anyway, we silently
116 // ignore CARGO_INCREMENTAL on anything but nightly. This allows users
117 // to always have CARGO_INCREMENTAL set without getting unexpected
118 // errors on stable/beta builds.
213a2bf0
JG
119 let is_nightly =
120 config.rustc()?.verbose_version.contains("-nightly") ||
121 config.rustc()?.verbose_version.contains("-dev");
122 let incremental_enabled = incremental_enabled && is_nightly;
357bb2de 123
cbf25a9b
AC
124 // Load up the jobserver that we'll use to manage our parallelism. This
125 // is the same as the GNU make implementation of a jobserver, and
126 // intentionally so! It's hoped that we can interact with GNU make and
127 // all share the same jobserver.
128 //
129 // Note that if we don't have a jobserver in our environment then we
130 // create our own, and we create it with `n-1` tokens because one token
131 // is ourself, a running process.
132 let jobserver = match config.jobserver_from_env() {
133 Some(c) => c.clone(),
134 None => Client::new(build_config.jobs as usize - 1).chain_err(|| {
135 "failed to create jobserver"
136 })?,
137 };
138
1e1412fd 139 Ok(Context {
0ae3a2b4 140 ws: ws,
77720032 141 host: host_layout,
5d0cb3f2 142 target: target_layout,
1e1412fd 143 resolve: resolve,
2d25fcac 144 packages: packages,
1e1412fd 145 config: config,
3f7b09cc
AC
146 target_info: TargetInfo::default(),
147 host_info: TargetInfo::default(),
b3ade7c7 148 compilation: Compilation::new(config),
919cddeb 149 build_state: Arc::new(BuildState::new(&build_config)),
ac4eddbb 150 build_config: build_config,
a40d3b03 151 fingerprints: HashMap::new(),
9e779198
AC
152 profiles: profiles,
153 compiled: HashSet::new(),
5a953eb0 154 build_scripts: HashMap::new(),
7c97c5bf 155 build_explicit_deps: HashMap::new(),
5ea7a97d 156 links: Links::new(),
e9c6b0a0 157 used_in_plugin: HashSet::new(),
a5bf3b88 158 incremental_enabled: incremental_enabled,
cbf25a9b 159 jobserver: jobserver,
f90d21f6 160 build_script_overridden: HashSet::new(),
67b3b444
NK
161
162 // TODO: Pre-Calculate these with a topo-sort, rather than lazy-calculating
e6649dfa 163 target_filenames: HashMap::new(),
67b3b444 164 target_metadatas: HashMap::new(),
1e1412fd
AC
165 })
166 }
167
3f7b09cc
AC
168 /// Prepare this context, ensuring that all filesystem directories are in
169 /// place.
0863469c 170 pub fn prepare(&mut self) -> CargoResult<()> {
3f7b09cc
AC
171 let _p = profile::start("preparing layout");
172
e95044e3 173 self.host.prepare().chain_err(|| {
23591fe5 174 internal("couldn't prepare build directories")
82655b46 175 })?;
23591fe5
LL
176 if let Some(ref mut target) = self.target {
177 target.prepare().chain_err(|| {
178 internal("couldn't prepare build directories")
179 })?;
3f7b09cc
AC
180 }
181
3b5ec888 182 self.compilation.host_deps_output = self.host.deps().to_path_buf();
7165bd58 183
0863469c
AC
184 let layout = self.target.as_ref().unwrap_or(&self.host);
185 self.compilation.root_output = layout.dest().to_path_buf();
186 self.compilation.deps_output = layout.deps().to_path_buf();
3f7b09cc
AC
187 Ok(())
188 }
189
190 /// Ensure that we've collected all target-specific information to compile
191 /// all the units mentioned in `units`.
192 pub fn probe_target_info(&mut self, units: &[Unit<'a>]) -> CargoResult<()> {
193 let mut crate_types = BTreeSet::new();
6e53b55d 194 let mut visited_units = HashSet::new();
3f7b09cc
AC
195 // pre-fill with `bin` for learning about tests (nothing may be
196 // explicitly `bin`) as well as `rlib` as it's the coalesced version of
197 // `lib` in the compiler and we're not sure which we'll see.
198 crate_types.insert("bin".to_string());
199 crate_types.insert("rlib".to_string());
200 for unit in units {
6e53b55d 201 self.visit_crate_type(unit, &mut crate_types, &mut visited_units)?;
3f7b09cc 202 }
47b25fd3 203 debug!("probe_target_info: crate_types={:?}", crate_types);
82655b46 204 self.probe_target_info_kind(&crate_types, Kind::Target)?;
d469bbcb 205 if self.requested_target().is_none() {
3f7b09cc
AC
206 self.host_info = self.target_info.clone();
207 } else {
82655b46 208 self.probe_target_info_kind(&crate_types, Kind::Host)?;
3f7b09cc
AC
209 }
210 Ok(())
211 }
212
213 fn visit_crate_type(&self,
214 unit: &Unit<'a>,
6e53b55d
GS
215 crate_types: &mut BTreeSet<String>,
216 visited_units: &mut HashSet<Unit<'a>>)
3f7b09cc 217 -> CargoResult<()> {
6e53b55d
GS
218 if !visited_units.insert(*unit) {
219 return Ok(());
220 }
3f7b09cc
AC
221 for target in unit.pkg.manifest().targets() {
222 crate_types.extend(target.rustc_crate_types().iter().map(|s| {
223 if *s == "lib" {
224 "rlib".to_string()
225 } else {
226 s.to_string()
227 }
228 }));
229 }
23591fe5 230 for dep in self.dep_targets(unit)? {
6e53b55d 231 self.visit_crate_type(&dep, crate_types, visited_units)?;
3f7b09cc
AC
232 }
233 Ok(())
234 }
235
236 fn probe_target_info_kind(&mut self,
237 crate_types: &BTreeSet<String>,
238 kind: Kind)
239 -> CargoResult<()> {
82655b46 240 let rustflags = env_args(self.config,
02625ba8 241 &self.build_config,
23591fe5 242 self.info(&kind),
02625ba8
NC
243 kind,
244 "RUSTFLAGS")?;
82655b46 245 let mut process = self.config.rustc()?.process();
a6dad622 246 process.arg("-")
856641cc 247 .arg("--crate-name").arg("___")
5955ea8a 248 .arg("--print=file-names")
f639d381 249 .args(&rustflags)
5955ea8a 250 .env_remove("RUST_LOG");
3f7b09cc 251
3f7b09cc 252 if kind == Kind::Target {
d469bbcb 253 process.arg("--target").arg(&self.target_triple());
3f7b09cc 254 }
f5d786e0 255
4cfaf9a5
MS
256 let crate_type_process = process.clone();
257
258 for crate_type in crate_types {
259 process.arg("--crate-type").arg(crate_type);
260 }
261
f5d786e0 262 let mut with_cfg = process.clone();
b1a96167 263 with_cfg.arg("--print=sysroot");
f5d786e0
AC
264 with_cfg.arg("--print=cfg");
265
b1a96167 266 let mut has_cfg_and_sysroot = true;
82655b46 267 let output = with_cfg.exec_with_output().or_else(|_| {
b1a96167 268 has_cfg_and_sysroot = false;
f5d786e0 269 process.exec_with_output()
e95044e3 270 }).chain_err(|| {
23591fe5 271 "failed to run `rustc` to learn about target-specific information"
82655b46 272 })?;
1e1412fd 273
a6dad622
AC
274 let error = str::from_utf8(&output.stderr).unwrap();
275 let output = str::from_utf8(&output.stdout).unwrap();
a162c088 276 let mut lines = output.lines();
3f7b09cc
AC
277 let mut map = HashMap::new();
278 for crate_type in crate_types {
4cfaf9a5
MS
279 let out = parse_crate_type(crate_type, error, &mut lines)?;
280 map.insert(crate_type.to_string(), out);
856641cc 281 }
3cbf141b 282
b1a96167
JM
283 if has_cfg_and_sysroot {
284 let line = match lines.next() {
285 Some(line) => line,
286 None => bail!("output of --print=sysroot missing when learning about \
287 target-specific information from rustc"),
288 };
289 let mut rustlib = PathBuf::from(line);
784d3154
JM
290 if kind == Kind::Host {
291 if cfg!(windows) {
292 rustlib.push("bin");
293 } else {
294 rustlib.push("lib");
295 }
296 self.compilation.host_dylib_path = Some(rustlib);
297 } else {
298 rustlib.push("lib");
299 rustlib.push("rustlib");
300 rustlib.push(self.target_triple());
301 rustlib.push("lib");
302 self.compilation.target_dylib_path = Some(rustlib);
303 }
b1a96167
JM
304 }
305
306 let cfg = if has_cfg_and_sysroot {
f5d786e0
AC
307 Some(try!(lines.map(Cfg::from_str).collect()))
308 } else {
309 None
310 };
311
3f7b09cc
AC
312 let info = match kind {
313 Kind::Target => &mut self.target_info,
314 Kind::Host => &mut self.host_info,
315 };
4cfaf9a5
MS
316 info.crate_type_process = Some(crate_type_process);
317 info.crate_types = RefCell::new(map);
3f7b09cc 318 info.cfg = cfg;
3a852a0f 319 Ok(())
1e1412fd
AC
320 }
321
e9c6b0a0
AC
322 /// Builds up the `used_in_plugin` internal to this context from the list of
323 /// top-level units.
324 ///
325 /// This will recursively walk `units` and all of their dependencies to
326 /// determine which crate are going to be used in plugins or not.
327 pub fn build_used_in_plugin_map(&mut self, units: &[Unit<'a>])
328 -> CargoResult<()> {
329 let mut visited = HashSet::new();
330 for unit in units {
82655b46 331 self.walk_used_in_plugin_map(unit,
4b82fdc0
NC
332 unit.target.for_host(),
333 &mut visited)?;
e9c6b0a0
AC
334 }
335 Ok(())
336 }
337
338 fn walk_used_in_plugin_map(&mut self,
339 unit: &Unit<'a>,
340 is_plugin: bool,
341 visited: &mut HashSet<(Unit<'a>, bool)>)
342 -> CargoResult<()> {
343 if !visited.insert((*unit, is_plugin)) {
344 return Ok(())
345 }
346 if is_plugin {
347 self.used_in_plugin.insert(*unit);
348 }
82655b46
SG
349 for unit in self.dep_targets(unit)? {
350 self.walk_used_in_plugin_map(&unit,
4b82fdc0
NC
351 is_plugin || unit.target.for_host(),
352 visited)?;
e9c6b0a0
AC
353 }
354 Ok(())
355 }
356
9f5d9b81 357 /// Returns the appropriate directory layout for either a plugin or not.
41579bad
AC
358 fn layout(&self, kind: Kind) -> &Layout {
359 match kind {
360 Kind::Host => &self.host,
361 Kind::Target => self.target.as_ref().unwrap_or(&self.host)
ff19a482
AC
362 }
363 }
364
41579bad
AC
365 /// Returns the directories where Rust crate dependencies are found for the
366 /// specified unit.
367 pub fn deps_dir(&self, unit: &Unit) -> &Path {
368 self.layout(unit.kind).deps()
369 }
370
371 /// Returns the directory for the specified unit where fingerprint
372 /// information is stored.
67b3b444 373 pub fn fingerprint_dir(&mut self, unit: &Unit<'a>) -> PathBuf {
41579bad
AC
374 let dir = self.pkg_dir(unit);
375 self.layout(unit.kind).fingerprint().join(dir)
376 }
377
378 /// Returns the appropriate directory layout for either a plugin or not.
67b3b444 379 pub fn build_script_dir(&mut self, unit: &Unit<'a>) -> PathBuf {
41579bad
AC
380 assert!(unit.target.is_custom_build());
381 assert!(!unit.profile.run_custom_build);
382 let dir = self.pkg_dir(unit);
383 self.layout(Kind::Host).build().join(dir)
384 }
385
386 /// Returns the appropriate directory layout for either a plugin or not.
67b3b444 387 pub fn build_script_out_dir(&mut self, unit: &Unit<'a>) -> PathBuf {
41579bad
AC
388 assert!(unit.target.is_custom_build());
389 assert!(unit.profile.run_custom_build);
390 let dir = self.pkg_dir(unit);
391 self.layout(unit.kind).build().join(dir).join("out")
392 }
393
a298346d
AC
394 pub fn host_deps(&self) -> &Path {
395 self.host.deps()
396 }
397
b8158cfd
JM
398 /// Return the root of the build output tree
399 pub fn target_root(&self) -> &Path {
400 self.host.dest()
401 }
402
d15aaa82
AC
403 /// Returns the appropriate output directory for the specified package and
404 /// target.
67b3b444 405 pub fn out_dir(&mut self, unit: &Unit<'a>) -> PathBuf {
2c089cf6 406 if unit.profile.doc {
41579bad
AC
407 self.layout(unit.kind).root().parent().unwrap().join("doc")
408 } else if unit.target.is_custom_build() {
409 self.build_script_dir(unit)
410 } else if unit.target.is_example() {
411 self.layout(unit.kind).examples().to_path_buf()
2c089cf6 412 } else {
41579bad
AC
413 self.deps_dir(unit).to_path_buf()
414 }
415 }
416
67b3b444 417 fn pkg_dir(&mut self, unit: &Unit<'a>) -> String {
41579bad
AC
418 let name = unit.pkg.package_id().name();
419 match self.target_metadata(unit) {
420 Some(meta) => format!("{}-{}", name, meta),
dd02aa34 421 None => format!("{}-{}", name, self.target_short_hash(unit)),
2c089cf6 422 }
d15aaa82
AC
423 }
424
a2d677ce
AK
425 /// Return the host triple for this context
426 pub fn host_triple(&self) -> &str {
d469bbcb 427 &self.build_config.host_triple
a2d677ce
AK
428 }
429
1a985a5b
AC
430 /// Return the target triple which this context is targeting.
431 pub fn target_triple(&self) -> &str {
23591fe5 432 self.requested_target().unwrap_or_else(|| self.host_triple())
1a985a5b
AC
433 }
434
a2d677ce
AK
435 /// Requested (not actual) target for the build
436 pub fn requested_target(&self) -> Option<&str> {
437 self.build_config.requested_target.as_ref().map(|s| &s[..])
438 }
439
dd02aa34
TH
440 /// Get the short hash based only on the PackageId
441 /// Used for the metadata when target_metadata returns None
442 pub fn target_short_hash(&self, unit: &Unit) -> String {
443 let hashable = unit.pkg.package_id().stable_hash(self.ws.root());
444 util::short_hash(&hashable)
445 }
446
9e779198 447 /// Get the metadata for a target in a specific profile
4650194d
NK
448 /// We build to the path: "{filename}-{target_metadata}"
449 /// We use a linking step to link/copy to a predictable filename
450 /// like `target/debug/libfoo.{a,so,rlib}` and such.
67b3b444
NK
451 pub fn target_metadata(&mut self, unit: &Unit<'a>) -> Option<Metadata> {
452 if let Some(cache) = self.target_metadatas.get(unit) {
453 return cache.clone()
454 }
455
456 let metadata = self.calc_target_metadata(unit);
457 self.target_metadatas.insert(*unit, metadata.clone());
458 metadata
459 }
460
461 fn calc_target_metadata(&mut self, unit: &Unit<'a>) -> Option<Metadata> {
530f2dd4
NK
462 // No metadata for dylibs because of a couple issues
463 // - OSX encodes the dylib name in the executable
464 // - Windows rustc multiple files of which we can't easily link all of them
4650194d 465 //
43833213 466 // Two exceptions
4650194d
NK
467 // 1) Upstream dependencies (we aren't exporting + need to resolve name conflict)
468 // 2) __CARGO_DEFAULT_LIB_METADATA env var
469 //
470 // Note, though, that the compiler's build system at least wants
471 // path dependencies (eg libstd) to have hashes in filenames. To account for
472 // that we have an extra hack here which reads the
dc8d5d38 473 // `__CARGO_DEFAULT_LIB_METADATA` environment variable and creates a
4650194d
NK
474 // hash in the filename if that's present.
475 //
476 // This environment variable should not be relied on! It's
477 // just here for rustbuild. We need a more principled method
478 // doing this eventually.
dc8d5d38 479 let __cargo_default_lib_metadata = env::var("__CARGO_DEFAULT_LIB_METADATA");
4650194d 480 if !unit.profile.test &&
fccaffb1 481 (unit.target.is_dylib() || unit.target.is_cdylib()) &&
4650194d 482 unit.pkg.package_id().source_id().is_path() &&
dc8d5d38 483 !__cargo_default_lib_metadata.is_ok() {
530f2dd4
NK
484 return None;
485 }
486
0cc39aae
AC
487 let mut hasher = SipHasher::new_with_keys(0, 0);
488
489 // Unique metadata per (name, source, version) triple. This'll allow us
490 // to pull crates from anywhere w/o worrying about conflicts
dd02aa34 491 unit.pkg.package_id().stable_hash(self.ws.root()).hash(&mut hasher);
0cc39aae 492
d70ca210
AL
493 // Add package properties which map to environment variables
494 // exposed by Cargo
495 let manifest_metadata = unit.pkg.manifest().metadata();
496 manifest_metadata.authors.hash(&mut hasher);
497 manifest_metadata.description.hash(&mut hasher);
498 manifest_metadata.homepage.hash(&mut hasher);
499
0cc39aae
AC
500 // Also mix in enabled features to our metadata. This'll ensure that
501 // when changing feature sets each lib is separately cached.
50f1c172 502 self.resolve.features_sorted(unit.pkg.package_id()).hash(&mut hasher);
0cc39aae 503
69e0d9f7 504 // Mix in the target-metadata of all the dependencies of this target
f90d21f6 505 if let Ok(deps) = self.dep_targets(unit) {
7336e322
NK
506 let mut deps_metadata = deps.into_iter().map(|dep_unit| {
507 self.target_metadata(&dep_unit)
508 }).collect::<Vec<_>>();
509 deps_metadata.sort();
510 deps_metadata.hash(&mut hasher);
46a5fe9a
NK
511 }
512
0cc39aae
AC
513 // Throw in the profile we're compiling with. This helps caching
514 // panic=abort and panic=unwind artifacts, additionally with various
515 // settings like debuginfo and whatnot.
516 unit.profile.hash(&mut hasher);
517
73216cb9
AC
518 // Artifacts compiled for the host should have a different metadata
519 // piece than those compiled for the target, so make sure we throw in
520 // the unit's `kind` as well
521 unit.kind.hash(&mut hasher);
522
0cc39aae
AC
523 // Finally throw in the target name/kind. This ensures that concurrent
524 // compiles of targets in the same crate don't collide.
525 unit.target.name().hash(&mut hasher);
526 unit.target.kind().hash(&mut hasher);
527
23591fe5 528 if let Ok(rustc) = self.config.rustc() {
fee7c68e
MAP
529 rustc.verbose_version.hash(&mut hasher);
530 }
531
dc8d5d38
MAP
532 // Seed the contents of __CARGO_DEFAULT_LIB_METADATA to the hasher if present.
533 // This should be the release channel, to get a different hash for each channel.
534 if let Ok(ref channel) = __cargo_default_lib_metadata {
535 channel.hash(&mut hasher);
536 }
537
d2ca374c 538 Some(Metadata(hasher.finish()))
9e779198
AC
539 }
540
76ff7baa 541 /// Returns the file stem for a given target/profile combo (with metadata)
67b3b444 542 pub fn file_stem(&mut self, unit: &Unit<'a>) -> String {
659f8244 543 match self.target_metadata(unit) {
0cc39aae
AC
544 Some(ref metadata) => format!("{}-{}", unit.target.crate_name(),
545 metadata),
530f2dd4
NK
546 None => self.bin_stem(unit),
547 }
548 }
549
76ff7baa 550 /// Returns the bin stem for a given target (without metadata)
530f2dd4
NK
551 fn bin_stem(&self, unit: &Unit) -> String {
552 if unit.target.allows_underscores() {
553 unit.target.name().to_string()
554 } else {
555 unit.target.crate_name()
556 }
557 }
558
76ff7baa
NK
559 /// Returns a tuple with the directory and name of the hard link we expect
560 /// our target to be copied to. Eg, file_stem may be out_dir/deps/foo-abcdef
561 /// and link_stem would be out_dir/foo
56967a26 562 /// This function returns it in two parts so the caller can add prefix/suffix
76ff7baa
NK
563 /// to filename separately
564
565 /// Returns an Option because in some cases we don't want to link
566 /// (eg a dependent lib)
67b3b444 567 pub fn link_stem(&mut self, unit: &Unit<'a>) -> Option<(PathBuf, String)> {
530f2dd4
NK
568 let src_dir = self.out_dir(unit);
569 let bin_stem = self.bin_stem(unit);
570 let file_stem = self.file_stem(unit);
571
572 // We currently only lift files up from the `deps` directory. If
573 // it was compiled into something like `example/` or `doc/` then
574 // we don't want to link it up.
575 if src_dir.ends_with("deps") {
576 // Don't lift up library dependencies
3cbf141b
AC
577 if self.ws.members().find(|&p| p == unit.pkg).is_none() &&
578 !unit.target.is_bin() {
530f2dd4
NK
579 None
580 } else {
581 Some((
582 src_dir.parent().unwrap().to_owned(),
583 if unit.profile.test {file_stem} else {bin_stem},
584 ))
659f8244 585 }
530f2dd4
NK
586 } else if bin_stem == file_stem {
587 None
23591fe5
LL
588 } else if src_dir.ends_with("examples")
589 || src_dir.parent().unwrap().ends_with("build") {
530f2dd4
NK
590 Some((src_dir, bin_stem))
591 } else {
592 None
9e779198
AC
593 }
594 }
595
596 /// Return the filenames that the given target for the given profile will
530f2dd4
NK
597 /// generate as a list of 3-tuples (filename, link_dst, linkable)
598 /// filename: filename rustc compiles to. (Often has metadata suffix).
599 /// link_dst: Optional file to link/copy the result to (without metadata suffix)
600 /// linkable: Whether possible to link against file (eg it's a library)
e6649dfa
AC
601 pub fn target_filenames(&mut self, unit: &Unit<'a>)
602 -> CargoResult<Arc<Vec<(PathBuf, Option<PathBuf>, bool)>>> {
603 if let Some(cache) = self.target_filenames.get(unit) {
23591fe5 604 return Ok(Arc::clone(cache))
e6649dfa
AC
605 }
606
67b3b444
NK
607 let result = self.calc_target_filenames(unit);
608 if let Ok(ref ret) = result {
23591fe5 609 self.target_filenames.insert(*unit, Arc::clone(ret));
67b3b444
NK
610 }
611 result
612 }
613
614 fn calc_target_filenames(&mut self, unit: &Unit<'a>)
615 -> CargoResult<Arc<Vec<(PathBuf, Option<PathBuf>, bool)>>> {
530f2dd4 616 let out_dir = self.out_dir(unit);
659f8244 617 let stem = self.file_stem(unit);
530f2dd4 618 let link_stem = self.link_stem(unit);
3f7b09cc
AC
619 let info = if unit.target.for_host() {
620 &self.host_info
659f8244 621 } else {
3f7b09cc 622 &self.target_info
659f8244 623 };
1e1412fd 624
8defed61 625 let mut ret = Vec::new();
3f7b09cc
AC
626 let mut unsupported = Vec::new();
627 {
4b82fdc0 628 if unit.profile.check {
655decc0
NC
629 let filename = out_dir.join(format!("lib{}.rmeta", stem));
630 let link_dst = link_stem.clone().map(|(ld, ls)| {
631 ld.join(format!("lib{}.rmeta", ls))
632 });
633 ret.push((filename, link_dst, true));
4b82fdc0 634 } else {
655decc0
NC
635 let mut add = |crate_type: &str, linkable: bool| -> CargoResult<()> {
636 let crate_type = if crate_type == "lib" {"rlib"} else {crate_type};
4cfaf9a5
MS
637 let mut crate_types = info.crate_types.borrow_mut();
638 let entry = crate_types.entry(crate_type.to_string());
639 let crate_type_info = match entry {
640 Entry::Occupied(o) => &*o.into_mut(),
641 Entry::Vacant(v) => {
23591fe5 642 let value = info.discover_crate_type(v.key())?;
4cfaf9a5
MS
643 &*v.insert(value)
644 }
645 };
646 match *crate_type_info {
647 Some((ref prefix, ref suffix)) => {
655decc0
NC
648 let filename = out_dir.join(format!("{}{}{}", prefix, stem, suffix));
649 let link_dst = link_stem.clone().map(|(ld, ls)| {
650 ld.join(format!("{}{}{}", prefix, ls, suffix))
651 });
652 ret.push((filename, link_dst, linkable));
653 Ok(())
654 }
655 // not supported, don't worry about it
4cfaf9a5 656 None => {
655decc0
NC
657 unsupported.push(crate_type.to_string());
658 Ok(())
659 }
655decc0
NC
660 }
661 };
662
4b82fdc0 663 match *unit.target.kind() {
4b82fdc0
NC
664 TargetKind::Bin |
665 TargetKind::CustomBuild |
47b25fd3 666 TargetKind::ExampleBin |
4b82fdc0
NC
667 TargetKind::Bench |
668 TargetKind::Test => {
669 add("bin", false)?;
670 }
47b25fd3
KA
671 TargetKind::Lib(..) |
672 TargetKind::ExampleLib(..)
673 if unit.profile.test => {
4b82fdc0
NC
674 add("bin", false)?;
675 }
47b25fd3
KA
676 TargetKind::ExampleLib(ref kinds) |
677 TargetKind::Lib(ref kinds) => {
678 for kind in kinds {
679 add(kind.crate_type(), kind.linkable())?;
4b82fdc0 680 }
7c60da4e 681 }
7c60da4e 682 }
85b0d0a4 683 }
1e1412fd 684 }
3f7b09cc 685 if ret.is_empty() {
23591fe5 686 if !unsupported.is_empty() {
3f7b09cc
AC
687 bail!("cannot produce {} for `{}` as the target `{}` \
688 does not support these crate types",
d469bbcb 689 unsupported.join(", "), unit.pkg, self.target_triple())
3f7b09cc
AC
690 }
691 bail!("cannot compile `{}` as the target `{}` does not \
692 support any of the output crate types",
d469bbcb 693 unit.pkg, self.target_triple());
3f7b09cc 694 }
530f2dd4 695 info!("Target filenames: {:?}", ret);
e6649dfa 696
67b3b444 697 Ok(Arc::new(ret))
1e1412fd
AC
698 }
699
f90d21f6
AC
700 /// For a package, return all targets which are registered as dependencies
701 /// for that package.
702 pub fn dep_targets(&self, unit: &Unit<'a>) -> CargoResult<Vec<Unit<'a>>> {
703 if unit.profile.run_custom_build {
704 return self.dep_run_custom_build(unit)
705 } else if unit.profile.doc && !unit.profile.test {
706 return self.doc_deps(unit);
707 }
708
659f8244 709 let id = unit.pkg.package_id();
54d738b0 710 let deps = self.resolve.deps(id);
f90d21f6 711 let mut ret = deps.filter(|dep| {
659f8244 712 unit.pkg.dependencies().iter().filter(|d| {
0a4fbbf2 713 d.name() == dep.name() && d.version_req().matches(dep.version())
35a7006a 714 }).any(|d| {
cfe8223c
JK
715 // If this target is a build command, then we only want build
716 // dependencies, otherwise we want everything *other than* build
717 // dependencies.
659f8244
AC
718 if unit.target.is_custom_build() != d.is_build() {
719 return false
720 }
cfe8223c
JK
721
722 // If this dependency is *not* a transitive dependency, then it
723 // only applies to test/example targets
659f8244
AC
724 if !d.is_transitive() && !unit.target.is_test() &&
725 !unit.target.is_example() && !unit.profile.test {
726 return false
727 }
cfe8223c 728
06589a86
NF
729 // If this dependency is only available for certain platforms,
730 // make sure we're only enabling it for that platform.
659f8244
AC
731 if !self.dep_platform_activated(d, unit.kind) {
732 return false
733 }
06589a86 734
70152d80
AC
735 // If the dependency is optional, then we're only activating it
736 // if the corresponding feature was activated
50f1c172
AK
737 if d.is_optional() && !self.resolve.features(id).contains(d.name()) {
738 return false;
659f8244 739 }
70152d80 740
659f8244
AC
741 // If we've gotten past all that, then this dependency is
742 // actually used!
743 true
35a7006a 744 })
dc5671d3 745 }).filter_map(|id| {
078b6707
AC
746 match self.get_package(id) {
747 Ok(pkg) => {
748 pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
4b82fdc0 749 let unit = Unit {
078b6707
AC
750 pkg: pkg,
751 target: t,
02625ba8 752 profile: self.lib_or_check_profile(unit, t),
078b6707 753 kind: unit.kind.for_target(t),
4b82fdc0
NC
754 };
755 Ok(unit)
078b6707 756 })
659f8244 757 }
078b6707
AC
758 Err(e) => Some(Err(e))
759 }
f90d21f6 760 }).collect::<CargoResult<Vec<_>>>()?;
b5f23288 761
ef3215ab
AC
762 // If this target is a build script, then what we've collected so far is
763 // all we need. If this isn't a build script, then it depends on the
764 // build script if there is one.
659f8244 765 if unit.target.is_custom_build() {
078b6707 766 return Ok(ret)
9e779198 767 }
ef3215ab 768 ret.extend(self.dep_build_script(unit));
9e779198 769
b5f23288
AC
770 // If this target is a binary, test, example, etc, then it depends on
771 // the library of the same package. The call to `resolve.deps` above
772 // didn't include `pkg` in the return values, so we need to special case
773 // it here and see if we need to push `(pkg, pkg_lib_target)`.
fb1736ef 774 if unit.target.is_lib() && !unit.profile.doc {
078b6707 775 return Ok(ret)
b5f23288 776 }
659f8244 777 ret.extend(self.maybe_lib(unit));
9e779198 778
fb8a3e32 779 // Integration tests/benchmarks require binaries to be built
659f8244
AC
780 if unit.profile.test &&
781 (unit.target.is_test() || unit.target.is_bench()) {
5f0d8a55
JB
782 ret.extend(unit.pkg.targets().iter().filter(|t| {
783 let no_required_features = Vec::new();
784
785 t.is_bin() &&
786 // Skip binaries with required features that have not been selected.
787 t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
fbc00c65 788 self.resolve.features(id).contains(f)
5f0d8a55
JB
789 })
790 }).map(|t| {
659f8244
AC
791 Unit {
792 pkg: unit.pkg,
793 target: t,
830b8af4 794 profile: self.lib_profile(),
659f8244
AC
795 kind: unit.kind.for_target(t),
796 }
797 }));
9e779198 798 }
078b6707 799 Ok(ret)
1e1412fd 800 }
9f5d9b81 801
ef3215ab
AC
802 /// Returns the dependencies needed to run a build script.
803 ///
804 /// The `unit` provided must represent an execution of a build script, and
805 /// the returned set of units must all be run before `unit` is run.
078b6707
AC
806 pub fn dep_run_custom_build(&self, unit: &Unit<'a>)
807 -> CargoResult<Vec<Unit<'a>>> {
ef3215ab
AC
808 // If this build script's execution has been overridden then we don't
809 // actually depend on anything, we've reached the end of the dependency
810 // chain as we've got all the info we're gonna get.
811 let key = (unit.pkg.package_id().clone(), unit.kind);
f90d21f6 812 if self.build_script_overridden.contains(&key) {
078b6707 813 return Ok(Vec::new())
ef3215ab
AC
814 }
815
816 // When not overridden, then the dependencies to run a build script are:
817 //
818 // 1. Compiling the build script itself
819 // 2. For each immediate dependency of our package which has a `links`
820 // key, the execution of that build script.
659f8244
AC
821 let not_custom_build = unit.pkg.targets().iter().find(|t| {
822 !t.is_custom_build()
823 }).unwrap();
824 let tmp = Unit {
825 target: not_custom_build,
826 profile: &self.profiles.dev,
827 ..*unit
828 };
82655b46 829 let deps = self.dep_targets(&tmp)?;
078b6707 830 Ok(deps.iter().filter_map(|unit| {
659f8244
AC
831 if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
832 return None
833 }
ef3215ab
AC
834 self.dep_build_script(unit)
835 }).chain(Some(Unit {
659f8244 836 profile: self.build_script_profile(unit.pkg.package_id()),
ef3215ab 837 kind: Kind::Host, // build scripts always compiled for the host
659f8244 838 ..*unit
078b6707 839 })).collect())
659f8244
AC
840 }
841
8350cd17 842 /// Returns the dependencies necessary to document a package
078b6707 843 fn doc_deps(&self, unit: &Unit<'a>) -> CargoResult<Vec<Unit<'a>>> {
54d738b0 844 let deps = self.resolve.deps(unit.pkg.package_id()).filter(|dep| {
659f8244 845 unit.pkg.dependencies().iter().filter(|d| {
8350cd17 846 d.name() == dep.name()
d6a9aaf3 847 }).any(|dep| {
b43d2869 848 match dep.kind() {
659f8244
AC
849 DepKind::Normal => self.dep_platform_activated(dep,
850 unit.kind),
b43d2869
AC
851 _ => false,
852 }
d6a9aaf3 853 })
078b6707
AC
854 }).map(|dep| {
855 self.get_package(dep)
8350cd17
AC
856 });
857
858 // To document a library, we depend on dependencies actually being
859 // built. If we're documenting *all* libraries, then we also depend on
860 // the documentation of the library being built.
861 let mut ret = Vec::new();
078b6707 862 for dep in deps {
82655b46 863 let dep = dep?;
078b6707
AC
864 let lib = match dep.targets().iter().find(|t| t.is_lib()) {
865 Some(lib) => lib,
866 None => continue,
867 };
659f8244
AC
868 ret.push(Unit {
869 pkg: dep,
870 target: lib,
830b8af4 871 profile: self.lib_profile(),
659f8244
AC
872 kind: unit.kind.for_target(lib),
873 });
8350cd17 874 if self.build_config.doc_all {
659f8244
AC
875 ret.push(Unit {
876 pkg: dep,
877 target: lib,
878 profile: &self.profiles.doc,
879 kind: unit.kind.for_target(lib),
880 });
8350cd17
AC
881 }
882 }
883
884 // Be sure to build/run the build script for documented libraries as
ef3215ab 885 ret.extend(self.dep_build_script(unit));
12730033
AC
886
887 // If we document a binary, we need the library available
659f8244
AC
888 if unit.target.is_bin() {
889 ret.extend(self.maybe_lib(unit));
12730033 890 }
078b6707 891 Ok(ret)
8350cd17
AC
892 }
893
ef3215ab
AC
894 /// If a build script is scheduled to be run for the package specified by
895 /// `unit`, this function will return the unit to run that build script.
659f8244 896 ///
ef3215ab
AC
897 /// Overriding a build script simply means that the running of the build
898 /// script itself doesn't have any dependencies, so even in that case a unit
899 /// of work is still returned. `None` is only returned if the package has no
900 /// build script.
901 fn dep_build_script(&self, unit: &Unit<'a>) -> Option<Unit<'a>> {
902 unit.pkg.targets().iter().find(|t| t.is_custom_build()).map(|t| {
903 Unit {
904 pkg: unit.pkg,
905 target: t,
906 profile: &self.profiles.custom_build,
907 kind: unit.kind,
908 }
659f8244
AC
909 })
910 }
911
912 fn maybe_lib(&self, unit: &Unit<'a>) -> Option<Unit<'a>> {
913 unit.pkg.targets().iter().find(|t| t.linkable()).map(|t| {
914 Unit {
915 pkg: unit.pkg,
916 target: t,
02625ba8 917 profile: self.lib_or_check_profile(unit, t),
659f8244
AC
918 kind: unit.kind.for_target(t),
919 }
920 })
921 }
922
a3d056db
AC
923 fn dep_platform_activated(&self, dep: &Dependency, kind: Kind) -> bool {
924 // If this dependency is only available for certain platforms,
925 // make sure we're only enabling it for that platform.
f5d786e0
AC
926 let platform = match dep.platform() {
927 Some(p) => p,
928 None => return true,
929 };
930 let (name, info) = match kind {
a2d677ce
AK
931 Kind::Host => (self.host_triple(), &self.host_info),
932 Kind::Target => (self.target_triple(), &self.target_info),
f5d786e0
AC
933 };
934 platform.matches(name, info.cfg.as_ref().map(|cfg| &cfg[..]))
a3d056db
AC
935 }
936
c2b23512 937 /// Gets a package for the given package id.
078b6707
AC
938 pub fn get_package(&self, id: &PackageId) -> CargoResult<&'a Package> {
939 self.packages.get(id)
c2b23512
AC
940 }
941
ac4eddbb 942 /// Get the user-specified linker for a particular host or target
5a04a4d4
MB
943 pub fn linker(&self, kind: Kind) -> Option<&Path> {
944 self.target_config(kind).linker.as_ref().map(|s| s.as_ref())
ac4eddbb
AC
945 }
946
947 /// Get the user-specified `ar` program for a particular host or target
5a04a4d4
MB
948 pub fn ar(&self, kind: Kind) -> Option<&Path> {
949 self.target_config(kind).ar.as_ref().map(|s| s.as_ref())
ac4eddbb
AC
950 }
951
23587ee7
AC
952 /// Get the list of cfg printed out from the compiler for the specified kind
953 pub fn cfg(&self, kind: Kind) -> &[Cfg] {
954 let info = match kind {
955 Kind::Host => &self.host_info,
956 Kind::Target => &self.target_info,
957 };
958 info.cfg.as_ref().map(|s| &s[..]).unwrap_or(&[])
959 }
960
ac4eddbb
AC
961 /// Get the target configuration for a particular host or target
962 fn target_config(&self, kind: Kind) -> &TargetConfig {
963 match kind {
38d14a59
AC
964 Kind::Host => &self.build_config.host,
965 Kind::Target => &self.build_config.target,
ac4eddbb
AC
966 }
967 }
5d0cb3f2
AC
968
969 /// Number of jobs specified for this build
970 pub fn jobs(&self) -> u32 { self.build_config.jobs }
971
830b8af4 972 pub fn lib_profile(&self) -> &'a Profile {
75848a2a
AC
973 let (normal, test) = if self.build_config.release {
974 (&self.profiles.release, &self.profiles.bench_deps)
9e779198 975 } else {
75848a2a
AC
976 (&self.profiles.dev, &self.profiles.test_deps)
977 };
978 if self.build_config.test {
979 test
980 } else {
981 normal
a40d3b03 982 }
9e779198
AC
983 }
984
02625ba8
NC
985 pub fn lib_or_check_profile(&self, unit: &Unit, target: &Target) -> &'a Profile {
986 if unit.profile.check && !target.is_custom_build() && !target.for_host() {
987 &self.profiles.check
988 } else {
989 self.lib_profile()
990 }
991 }
992
830b8af4 993 pub fn build_script_profile(&self, _pkg: &PackageId) -> &'a Profile {
183c59c0 994 // TODO: should build scripts always be built with the same library
9e779198 995 // profile? How is this controlled at the CLI layer?
830b8af4 996 self.lib_profile()
a40d3b03 997 }
e17933ec 998
30e91b57 999 pub fn incremental_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
3d19b89c
MW
1000 if self.incremental_enabled {
1001 if unit.pkg.package_id().source_id().is_path() {
1002 // Only enable incremental compilation for sources the user can modify.
1003 // For things that change infrequently, non-incremental builds yield
1004 // better performance.
1005 // (see also https://github.com/rust-lang/cargo/issues/3972)
1006 return Ok(vec![format!("-Zincremental={}",
1007 self.layout(unit.kind).incremental().display())]);
23591fe5
LL
1008 } else if unit.profile.codegen_units.is_none() {
1009 // For non-incremental builds we set a higher number of
1010 // codegen units so we get faster compiles. It's OK to do
1011 // so because the user has already opted into slower
1012 // runtime code by setting CARGO_INCREMENTAL.
1013 return Ok(vec![format!("-Ccodegen-units={}", ::num_cpus::get())]);
3d19b89c 1014 }
a5bf3b88 1015 }
3d19b89c
MW
1016
1017 Ok(vec![])
a5bf3b88
NM
1018 }
1019
2f01868a 1020 pub fn rustflags_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
e6e6f10e 1021 env_args(self.config, &self.build_config, self.info(&unit.kind), unit.kind, "RUSTFLAGS")
f639d381
AC
1022 }
1023
1024 pub fn rustdocflags_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
e6e6f10e 1025 env_args(self.config, &self.build_config, self.info(&unit.kind), unit.kind, "RUSTDOCFLAGS")
c25c1ae1 1026 }
a30f612e
AC
1027
1028 pub fn show_warnings(&self, pkg: &PackageId) -> bool {
62161797 1029 pkg.source_id().is_path() || self.config.extra_verbose()
a30f612e 1030 }
e6e6f10e 1031
1032 fn info(&self, kind: &Kind) -> &TargetInfo {
1033 match *kind {
1034 Kind::Host => &self.host_info,
1035 Kind::Target => &self.target_info,
1036 }
1037 }
c25c1ae1 1038}
e17933ec 1039
c25c1ae1
AC
1040// Acquire extra flags to pass to the compiler from the
1041// RUSTFLAGS environment variable and similar config values
f639d381
AC
1042fn env_args(config: &Config,
1043 build_config: &BuildConfig,
e6e6f10e 1044 target_info: &TargetInfo,
f639d381
AC
1045 kind: Kind,
1046 name: &str) -> CargoResult<Vec<String>> {
c25c1ae1
AC
1047 // We *want* to apply RUSTFLAGS only to builds for the
1048 // requested target architecture, and not to things like build
1049 // scripts and plugins, which may be for an entirely different
1050 // architecture. Cargo's present architecture makes it quite
1051 // hard to only apply flags to things that are not build
1052 // scripts and plugins though, so we do something more hacky
1053 // instead to avoid applying the same RUSTFLAGS to multiple targets
1054 // arches:
1055 //
1056 // 1) If --target is not specified we just apply RUSTFLAGS to
1057 // all builds; they are all going to have the same target.
1058 //
1059 // 2) If --target *is* specified then we only apply RUSTFLAGS
1060 // to compilation units with the Target kind, which indicates
1061 // it was chosen by the --target flag.
1062 //
1063 // This means that, e.g. even if the specified --target is the
1064 // same as the host, build scripts in plugins won't get
1065 // RUSTFLAGS.
1066 let compiling_with_target = build_config.requested_target.is_some();
1067 let is_target_kind = kind == Kind::Target;
1068
1069 if compiling_with_target && !is_target_kind {
1070 // This is probably a build script or plugin and we're
1071 // compiling with --target. In this scenario there are
1072 // no rustflags we can apply.
1073 return Ok(Vec::new());
1074 }
e17933ec 1075
c25c1ae1 1076 // First try RUSTFLAGS from the environment
23591fe5
LL
1077 if let Ok(a) = env::var(name) {
1078 let args = a.split(' ')
c25c1ae1
AC
1079 .map(str::trim)
1080 .filter(|s| !s.is_empty())
1081 .map(str::to_string);
1082 return Ok(args.collect());
1083 }
e17933ec 1084
e6e6f10e 1085 let mut rustflags = Vec::new();
1086
f639d381 1087 let name = name.chars().flat_map(|c| c.to_lowercase()).collect::<String>();
fccaffb1 1088 // Then the target.*.rustflags value...
e9a5fb14
JA
1089 let target = build_config.requested_target.as_ref().unwrap_or(&build_config.host_triple);
1090 let key = format!("target.{}.{}", target, name);
f440704e
IB
1091 if let Some(args) = config.get_list_or_split_string(&key)? {
1092 let args = args.val.into_iter();
e6e6f10e 1093 rustflags.extend(args);
1094 }
1095 // ...including target.'cfg(...)'.rustflags
1096 if let Some(ref target_cfg) = target_info.cfg {
1097 if let Some(table) = config.get_table("target")? {
828247ac 1098 let cfgs = table.val.keys().filter_map(|t| {
23591fe5 1099 if t.starts_with("cfg(") && t.ends_with(')') {
828247ac 1100 let cfg = &t[4..t.len() - 1];
1101 CfgExpr::from_str(cfg)
1102 .ok()
1103 .and_then(|c| if c.matches(target_cfg) { Some(t) } else { None })
1104 } else {
1105 None
1106 }
1107 });
1108 for n in cfgs {
1109 let key = format!("target.{}.{}", n, name);
e6e6f10e 1110 if let Some(args) = config.get_list_or_split_string(&key)? {
1111 let args = args.val.into_iter();
1112 rustflags.extend(args);
1113 }
1114 }
1115 }
1116 }
1117
1118 if !rustflags.is_empty() {
1119 return Ok(rustflags);
e9a5fb14
JA
1120 }
1121
1122 // Then the build.rustflags value
f639d381 1123 let key = format!("build.{}", name);
f440704e
IB
1124 if let Some(args) = config.get_list_or_split_string(&key)? {
1125 let args = args.val.into_iter();
c25c1ae1 1126 return Ok(args.collect());
e17933ec 1127 }
c25c1ae1
AC
1128
1129 Ok(Vec::new())
1e1412fd 1130}
0cc39aae
AC
1131
1132impl fmt::Display for Metadata {
1133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1134 write!(f, "{:016x}", self.0)
1135 }
1136}
4cfaf9a5
MS
1137
1138fn parse_crate_type(
1139 crate_type: &str,
1140 error: &str,
1141 lines: &mut str::Lines,
1142) -> CargoResult<Option<(String, String)>> {
1143 let not_supported = error.lines().any(|line| {
1144 (line.contains("unsupported crate type") ||
1145 line.contains("unknown crate type")) &&
1146 line.contains(crate_type)
1147 });
1148 if not_supported {
1149 return Ok(None);
1150 }
1151 let line = match lines.next() {
1152 Some(line) => line,
1153 None => bail!("malformed output when learning about \
1154 crate-type {} information", crate_type),
1155 };
1156 let mut parts = line.trim().split("___");
1157 let prefix = parts.next().unwrap();
1158 let suffix = match parts.next() {
1159 Some(part) => part,
1160 None => bail!("output of --print=file-names has changed in \
1161 the compiler, cannot parse"),
1162 };
1163
1164 Ok(Some((prefix.to_string(), suffix.to_string())))
1165}