diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index 0ee88e8d4b4..6aa37a4f3ff 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -1680,7 +1680,7 @@ pub static RUSTC: Rustc = Rustc::new( /// The rustc host such as `x86_64-unknown-linux-gnu`. pub fn rustc_host() -> String { - RUSTC.with(|r| r.host.clone()) + RUSTC.with(|r| r.host.to_string()) } pub fn is_nightly() -> bool { diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index 958f8c1cab5..d39294660ce 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -1,17 +1,16 @@ use std::cell::RefCell; -use std::path::Path; use serde::ser; +use crate::core::compiler::{CompileKind, CompileTarget}; use crate::util::ProcessBuilder; -use crate::util::{CargoResult, CargoResultExt, Config, RustfixDiagnosticServer}; +use crate::util::{CargoResult, Config, RustfixDiagnosticServer}; /// Configuration information for a rustc build. #[derive(Debug)] pub struct BuildConfig { - /// The target arch triple. - /// Default: host arch. - pub requested_target: Option, + /// The requested kind of compilation for this session + pub requested_kind: CompileKind, /// Number of rustc jobs to run in parallel. pub jobs: u32, /// `true` if we are building for release. @@ -46,36 +45,21 @@ impl BuildConfig { requested_target: &Option, mode: CompileMode, ) -> CargoResult { - let requested_target = match requested_target { - &Some(ref target) if target.ends_with(".json") => { - let path = Path::new(target).canonicalize().chain_err(|| { - failure::format_err!("Target path {:?} is not a valid file", target) - })?; - Some( - path.into_os_string() - .into_string() - .map_err(|_| failure::format_err!("Target path is not valid unicode"))?, - ) - } - other => other.clone(), + let requested_kind = match requested_target { + Some(s) => CompileKind::Target(CompileTarget::new(s)?), + None => match config.get_string("build.target")? { + Some(cfg) => { + let value = if cfg.val.ends_with(".json") { + let path = cfg.definition.root(config).join(&cfg.val); + path.to_str().expect("must be utf-8 in toml").to_string() + } else { + cfg.val + }; + CompileKind::Target(CompileTarget::new(&value)?) + } + None => CompileKind::Host, + }, }; - if let Some(ref s) = requested_target { - if s.trim().is_empty() { - failure::bail!("target was empty") - } - } - let cfg_target = match config.get_string("build.target")? { - Some(ref target) if target.val.ends_with(".json") => { - let path = target.definition.root(config).join(&target.val); - let path_string = path - .into_os_string() - .into_string() - .map_err(|_| failure::format_err!("Target path is not valid unicode")); - Some(path_string?) - } - other => other.map(|t| t.val), - }; - let target = requested_target.or(cfg_target); if jobs == Some(0) { failure::bail!("jobs must be at least 1") @@ -91,7 +75,7 @@ impl BuildConfig { let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32); Ok(BuildConfig { - requested_target: target, + requested_kind, jobs, release: false, mode, diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 7333b08c680..c21938bbb3f 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -1,17 +1,15 @@ -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::str; - -use cargo_platform::Cfg; -use log::debug; - use crate::core::compiler::unit::UnitInterner; -use crate::core::compiler::{BuildConfig, BuildOutput, Kind, Unit}; +use crate::core::compiler::CompileTarget; +use crate::core::compiler::{BuildConfig, BuildOutput, CompileKind, Unit}; use crate::core::profiles::Profiles; -use crate::core::{Dependency, Workspace}; +use crate::core::{Dependency, InternedString, Workspace}; use crate::core::{PackageId, PackageSet}; use crate::util::errors::CargoResult; -use crate::util::{profile, Config, Rustc}; +use crate::util::{Config, Rustc}; +use cargo_platform::Cfg; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use std::str; mod target_info; pub use self::target_info::{FileFlavor, TargetInfo}; @@ -33,15 +31,24 @@ pub struct BuildContext<'a, 'cfg> { pub extra_compiler_args: HashMap, Vec>, pub packages: &'a PackageSet<'cfg>, - /// Information about the compiler. - pub rustc: Rustc, - /// Build information for the host arch. - pub host_config: TargetConfig, - /// Build information for the target. - pub target_config: TargetConfig, - pub target_info: TargetInfo, - pub host_info: TargetInfo, + /// Source of interning new units as they're created. pub units: &'a UnitInterner<'a>, + + /// Information about the compiler that we've detected on the local system. + pub rustc: Rustc, + + /// Build information for the "host", which is information about when + /// `rustc` is invoked without a `--target` flag. This is used for + /// procedural macros, build scripts, etc. + host_config: TargetConfig, + host_info: TargetInfo, + + /// Build information for targets that we're building for. This will be + /// empty if the `--target` flag is not passed, and currently also only ever + /// has at most one entry, but eventually we'd like to support multi-target + /// builds with Cargo. + target_config: HashMap, + target_info: HashMap, } impl<'a, 'cfg> BuildContext<'a, 'cfg> { @@ -57,19 +64,26 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { let rustc = config.load_global_rustc(Some(ws))?; let host_config = TargetConfig::new(config, &rustc.host)?; - let target_config = match build_config.requested_target.as_ref() { - Some(triple) => TargetConfig::new(config, triple)?, - None => host_config.clone(), - }; - let (host_info, target_info) = { - let _p = profile::start("BuildContext::probe_target_info"); - debug!("probe_target_info"); - let host_info = - TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::Host)?; - let target_info = - TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::Target)?; - (host_info, target_info) - }; + let host_info = TargetInfo::new( + config, + build_config.requested_kind, + &rustc, + CompileKind::Host, + )?; + let mut target_config = HashMap::new(); + let mut target_info = HashMap::new(); + if let CompileKind::Target(target) = build_config.requested_kind { + target_config.insert(target, TargetConfig::new(config, target.short_name())?); + target_info.insert( + target, + TargetInfo::new( + config, + build_config.requested_kind, + &rustc, + CompileKind::Target(target), + )?, + ); + } Ok(BuildContext { ws, @@ -88,38 +102,31 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { } /// Whether a dependency should be compiled for the host or target platform, - /// specified by `Kind`. - pub fn dep_platform_activated(&self, dep: &Dependency, kind: Kind) -> bool { + /// specified by `CompileKind`. + pub fn dep_platform_activated(&self, dep: &Dependency, kind: CompileKind) -> bool { // If this dependency is only available for certain platforms, // make sure we're only enabling it for that platform. let platform = match dep.platform() { Some(p) => p, None => return true, }; - let (name, info) = match kind { - Kind::Host => (self.host_triple(), &self.host_info), - Kind::Target => (self.target_triple(), &self.target_info), - }; - platform.matches(name, info.cfg()) + let name = kind.short_name(self); + platform.matches(&name, self.cfg(kind)) } /// Gets the user-specified linker for a particular host or target. - pub fn linker(&self, kind: Kind) -> Option<&Path> { + pub fn linker(&self, kind: CompileKind) -> Option<&Path> { self.target_config(kind).linker.as_ref().map(|s| s.as_ref()) } /// Gets the user-specified `ar` program for a particular host or target. - pub fn ar(&self, kind: Kind) -> Option<&Path> { + pub fn ar(&self, kind: CompileKind) -> Option<&Path> { self.target_config(kind).ar.as_ref().map(|s| s.as_ref()) } /// Gets the list of `cfg`s printed out from the compiler for the specified kind. - pub fn cfg(&self, kind: Kind) -> &[Cfg] { - let info = match kind { - Kind::Host => &self.host_info, - Kind::Target => &self.target_info, - }; - info.cfg() + pub fn cfg(&self, kind: CompileKind) -> &[Cfg] { + self.info(kind).cfg() } /// Gets the host architecture triple. @@ -128,23 +135,15 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { /// - machine: x86_64, /// - hardware-platform: unknown, /// - operating system: linux-gnu. - pub fn host_triple(&self) -> &str { - &self.rustc.host - } - - pub fn target_triple(&self) -> &str { - self.build_config - .requested_target - .as_ref() - .map(|s| s.as_str()) - .unwrap_or_else(|| self.host_triple()) + pub fn host_triple(&self) -> InternedString { + self.rustc.host } /// Gets the target configuration for a particular host or target. - fn target_config(&self, kind: Kind) -> &TargetConfig { + pub fn target_config(&self, kind: CompileKind) -> &TargetConfig { match kind { - Kind::Host => &self.host_config, - Kind::Target => &self.target_config, + CompileKind::Host => &self.host_config, + CompileKind::Target(s) => &self.target_config[&s], } } @@ -165,10 +164,10 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { pkg.source_id().is_path() || self.config.extra_verbose() } - fn info(&self, kind: Kind) -> &TargetInfo { + pub fn info(&self, kind: CompileKind) -> &TargetInfo { match kind { - Kind::Host => &self.host_info, - Kind::Target => &self.target_info, + CompileKind::Host => &self.host_info, + CompileKind::Target(s) => &self.target_info[&s], } } @@ -180,11 +179,8 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { /// /// `lib_name` is the `links` library name and `kind` is whether it is for /// Host or Target. - pub fn script_override(&self, lib_name: &str, kind: Kind) -> Option<&BuildOutput> { - match kind { - Kind::Host => self.host_config.overrides.get(lib_name), - Kind::Target => self.target_config.overrides.get(lib_name), - } + pub fn script_override(&self, lib_name: &str, kind: CompileKind) -> Option<&BuildOutput> { + self.target_config(kind).overrides.get(lib_name) } } diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index 2a4f5545be5..64b7f079ba2 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -4,7 +4,7 @@ use std::env; use std::path::PathBuf; use std::str::{self, FromStr}; -use crate::core::compiler::Kind; +use crate::core::compiler::CompileKind; use crate::core::TargetKind; use crate::util::{CargoResult, CargoResultExt, Config, ProcessBuilder, Rustc}; use cargo_platform::{Cfg, CfgExpr}; @@ -80,18 +80,11 @@ impl FileType { impl TargetInfo { pub fn new( config: &Config, - requested_target: &Option, + requested_kind: CompileKind, rustc: &Rustc, - kind: Kind, + kind: CompileKind, ) -> CargoResult { - let rustflags = env_args( - config, - requested_target, - &rustc.host, - None, - kind, - "RUSTFLAGS", - )?; + let rustflags = env_args(config, requested_kind, &rustc.host, None, kind, "RUSTFLAGS")?; let mut process = rustc.process(); process .arg("-") @@ -101,12 +94,8 @@ impl TargetInfo { .args(&rustflags) .env_remove("RUSTC_LOG"); - let target_triple = requested_target - .as_ref() - .map(|s| s.as_str()) - .unwrap_or(&rustc.host); - if kind == Kind::Target { - process.arg("--target").arg(target_triple); + if let CompileKind::Target(target) = kind { + process.arg("--target").arg(target.rustc_target()); } let crate_type_process = process.clone(); @@ -140,7 +129,7 @@ impl TargetInfo { }; let mut rustlib = PathBuf::from(line); let sysroot_libdir = match kind { - Kind::Host => { + CompileKind::Host => { if cfg!(windows) { rustlib.push("bin"); } else { @@ -148,10 +137,10 @@ impl TargetInfo { } rustlib } - Kind::Target => { + CompileKind::Target(target) => { rustlib.push("lib"); rustlib.push("rustlib"); - rustlib.push(target_triple); + rustlib.push(target.short_name()); rustlib.push("lib"); rustlib } @@ -175,7 +164,7 @@ impl TargetInfo { // information rustflags: env_args( config, - requested_target, + requested_kind, &rustc.host, Some(&cfg), kind, @@ -183,7 +172,7 @@ impl TargetInfo { )?, rustdocflags: env_args( config, - requested_target, + requested_kind, &rustc.host, Some(&cfg), kind, @@ -381,10 +370,10 @@ fn output_err_info(cmd: &ProcessBuilder, stdout: &str, stderr: &str) -> String { /// scripts, ...), even if it is the same as the target. fn env_args( config: &Config, - requested_target: &Option, + requested_kind: CompileKind, host_triple: &str, target_cfg: Option<&[Cfg]>, - kind: Kind, + kind: CompileKind, name: &str, ) -> CargoResult> { // We *want* to apply RUSTFLAGS only to builds for the @@ -406,10 +395,7 @@ fn env_args( // This means that, e.g., even if the specified --target is the // same as the host, build scripts in plugins won't get // RUSTFLAGS. - let compiling_with_target = requested_target.is_some(); - let is_target_kind = kind == Kind::Target; - - if compiling_with_target && !is_target_kind { + if !requested_kind.is_host() && kind.is_host() { // This is probably a build script or plugin and we're // compiling with --target. In this scenario there are // no rustflags we can apply. @@ -433,10 +419,10 @@ fn env_args( .flat_map(|c| c.to_lowercase()) .collect::(); // Then the target.*.rustflags value... - let target = requested_target - .as_ref() - .map(|s| s.as_str()) - .unwrap_or(host_triple); + let target = match &kind { + CompileKind::Host => host_triple, + CompileKind::Target(target) => target.short_name(), + }; let key = format!("target.{}.{}", target, name); if let Some(args) = config.get_list_or_split_string(&key)? { let args = args.val.into_iter(); diff --git a/src/cargo/core/compiler/build_plan.rs b/src/cargo/core/compiler/build_plan.rs index cfdd1a01523..d40d4a877f5 100644 --- a/src/cargo/core/compiler/build_plan.rs +++ b/src/cargo/core/compiler/build_plan.rs @@ -12,7 +12,7 @@ use std::path::PathBuf; use serde::Serialize; use super::context::OutputFile; -use super::{CompileMode, Context, Kind, Unit}; +use super::{CompileKind, CompileMode, Context, Unit}; use crate::core::TargetKind; use crate::util::{internal, CargoResult, ProcessBuilder}; @@ -21,7 +21,7 @@ struct Invocation { package_name: String, package_version: semver::Version, target_kind: TargetKind, - kind: Kind, + kind: CompileKind, compile_mode: CompileMode, deps: Vec, outputs: Vec, diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 2f0b190eb19..86afe35ac34 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -7,6 +7,7 @@ use cargo_platform::CfgExpr; use semver::Version; use super::BuildContext; +use crate::core::compiler::CompileKind; use crate::core::{Edition, InternedString, Package, PackageId, Target}; use crate::util::{self, join_paths, process, rustc::Rustc, CargoResult, Config, ProcessBuilder}; @@ -78,7 +79,10 @@ pub struct Compilation<'cfg> { } impl<'cfg> Compilation<'cfg> { - pub fn new<'a>(bcx: &BuildContext<'a, 'cfg>) -> CargoResult> { + pub fn new<'a>( + bcx: &BuildContext<'a, 'cfg>, + default_kind: CompileKind, + ) -> CargoResult> { let mut rustc = bcx.rustc.process(); let mut primary_unit_rustc_process = bcx.build_config.primary_unit_rustc.clone(); @@ -97,8 +101,8 @@ impl<'cfg> Compilation<'cfg> { root_output: PathBuf::from("/"), deps_output: PathBuf::from("/"), host_deps_output: PathBuf::from("/"), - host_dylib_path: bcx.host_info.sysroot_libdir.clone(), - target_dylib_path: bcx.target_info.sysroot_libdir.clone(), + host_dylib_path: bcx.info(CompileKind::Host).sysroot_libdir.clone(), + target_dylib_path: bcx.info(default_kind).sysroot_libdir.clone(), tests: Vec::new(), binaries: Vec::new(), extra_env: HashMap::new(), @@ -109,8 +113,8 @@ impl<'cfg> Compilation<'cfg> { rustc_process: rustc, primary_unit_rustc_process, host: bcx.host_triple().to_string(), - target: bcx.target_triple().to_string(), - target_runner: target_runner(bcx)?, + target: default_kind.short_name(bcx).to_string(), + target_runner: target_runner(bcx, default_kind)?, supports_rustdoc_crate_type: supports_rustdoc_crate_type(bcx.config, &bcx.rustc)?, }) } @@ -289,8 +293,11 @@ fn pre_version_component(v: &Version) -> String { ret } -fn target_runner(bcx: &BuildContext<'_, '_>) -> CargoResult)>> { - let target = bcx.target_triple(); +fn target_runner( + bcx: &BuildContext<'_, '_>, + kind: CompileKind, +) -> CargoResult)>> { + let target = kind.short_name(bcx); // try target.{}.runner let key = format!("target.{}.runner", target); @@ -303,7 +310,7 @@ fn target_runner(bcx: &BuildContext<'_, '_>) -> CargoResult bool { + match self { + CompileKind::Host => true, + _ => false, + } + } + + pub fn for_target(self, target: &Target) -> CompileKind { + // Once we start compiling for the `Host` kind we continue doing so, but + // if we are a `Target` kind and then we start compiling for a target + // that needs to be on the host we lift ourselves up to `Host`. + match self { + CompileKind::Host => CompileKind::Host, + CompileKind::Target(_) if target.for_host() => CompileKind::Host, + CompileKind::Target(n) => CompileKind::Target(n), + } + } + + /// Returns a "short" name for this kind, suitable for keying off + /// configuration in Cargo or presenting to users. + pub fn short_name(&self, bcx: &BuildContext<'_, '_>) -> &str { + match self { + CompileKind::Host => bcx.host_triple().as_str(), + CompileKind::Target(target) => target.short_name(), + } + } +} + +/// Abstraction for the representation of a compilation target that Cargo has. +/// +/// Compilation targets are one of two things right now: +/// +/// 1. A raw target string, like `x86_64-unknown-linux-gnu`. +/// 2. The path to a JSON file, such as `/path/to/my-target.json`. +/// +/// Raw target strings are typically dictated by `rustc` itself and represent +/// built-in targets. Custom JSON files are somewhat unstable, but supported +/// here in Cargo. Note that for JSON target files this `CompileTarget` stores a +/// full canonicalized path to the target. +/// +/// The main reason for this existence is to handle JSON target files where when +/// we call rustc we pass full paths but when we use it for Cargo's purposes +/// like naming directories or looking up configuration keys we only check the +/// file stem of JSON target files. For built-in rustc targets this is just an +/// uninterpreted string basically. +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] +pub struct CompileTarget { + name: InternedString, +} + +impl CompileTarget { + pub fn new(name: &str) -> CargoResult { + let name = name.trim(); + if name.is_empty() { + failure::bail!("target was empty"); + } + if !name.ends_with(".json") { + return Ok(CompileTarget { name: name.into() }); + } + + // If `name` ends in `.json` then it's likely a custom target + // specification. Canonicalize the path to ensure that different builds + // with different paths always produce the same result. + let path = Path::new(name) + .canonicalize() + .chain_err(|| failure::format_err!("target path {:?} is not a valid file", name))?; + + let name = path + .into_os_string() + .into_string() + .map_err(|_| failure::format_err!("target path is not valid unicode"))?; + Ok(CompileTarget { name: name.into() }) + } + + /// Returns the full unqualified name of this target, suitable for passing + /// to `rustc` directly. + /// + /// Typically this is pretty much the same as `short_name`, but for the case + /// of JSON target files this will be a full canonicalized path name for the + /// current filesystem. + pub fn rustc_target(&self) -> &str { + &self.name + } + + /// Returns a "short" version of the target name suitable for usage within + /// Cargo for configuration and such. + /// + /// This is typically the same as `rustc_target`, or the full name, but for + /// JSON target files this returns just the file stem (e.g. `foo` out of + /// `foo.json`) instead of the full path. + pub fn short_name(&self) -> &str { + // Flexible target specifications often point at json files, so if it + // looks like we've got one of those just use the file stem (the file + // name without ".json") as a short name for this target. Note that the + // `unwrap()` here should never trigger since we have a nonempty name + // and it starts as utf-8 so it's always utf-8 + if self.name.ends_with(".json") { + Path::new(&self.name).file_stem().unwrap().to_str().unwrap() + } else { + &self.name + } + } +} diff --git a/src/cargo/core/compiler/context/compilation_files.rs b/src/cargo/core/compiler/context/compilation_files.rs index 743d7d821c5..36cd3023b53 100644 --- a/src/cargo/core/compiler/context/compilation_files.rs +++ b/src/cargo/core/compiler/context/compilation_files.rs @@ -8,8 +8,8 @@ use std::sync::Arc; use lazycell::LazyCell; use log::info; -use super::{BuildContext, Context, FileFlavor, Kind, Layout}; -use crate::core::compiler::{CompileMode, Unit}; +use super::{BuildContext, CompileKind, Context, FileFlavor, Layout}; +use crate::core::compiler::{CompileMode, CompileTarget, Unit}; use crate::core::{TargetKind, Workspace}; use crate::util::{self, CargoResult}; @@ -54,7 +54,7 @@ pub struct CompilationFiles<'a, 'cfg> { /// The target directory layout for the host (and target if it is the same as host). pub(super) host: Layout, /// The target directory layout for the target (if different from then host). - pub(super) target: Option, + pub(super) target: HashMap, /// Additional directory to include a copy of the outputs. export_dir: Option, /// The root targets requested by the user on the command line (does not @@ -93,7 +93,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { pub(super) fn new( roots: &[Unit<'a>], host: Layout, - target: Option, + target: HashMap, export_dir: Option, ws: &'a Workspace<'cfg>, cx: &Context<'a, 'cfg>, @@ -119,10 +119,10 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { } /// Returns the appropriate directory layout for either a plugin or not. - pub fn layout(&self, kind: Kind) -> &Layout { + pub fn layout(&self, kind: CompileKind) -> &Layout { match kind { - Kind::Host => &self.host, - Kind::Target => self.target.as_ref().unwrap_or(&self.host), + CompileKind::Host => &self.host, + CompileKind::Target(target) => &self.target[&target], } } @@ -200,7 +200,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { assert!(unit.target.is_custom_build()); assert!(!unit.mode.is_run_custom_build()); let dir = self.pkg_dir(unit); - self.layout(Kind::Host).build().join(dir) + self.layout(CompileKind::Host).build().join(dir) } /// Returns the directory where information about running a build script @@ -345,11 +345,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { let out_dir = self.out_dir(unit); let link_stem = self.link_stem(unit); - let info = if unit.kind == Kind::Host { - &bcx.host_info - } else { - &bcx.target_info - }; + let info = bcx.info(unit.kind); let file_stem = self.file_stem(unit); let mut add = |crate_type: &str, flavor: FileFlavor| -> CargoResult<()> { @@ -358,8 +354,12 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { } else { crate_type }; - let file_types = - info.file_types(crate_type, flavor, unit.target.kind(), bcx.target_triple())?; + let file_types = info.file_types( + crate_type, + flavor, + unit.target.kind(), + unit.kind.short_name(bcx), + )?; match file_types { Some(types) => { @@ -432,14 +432,14 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { does not support these crate types", unsupported.join(", "), unit.pkg, - bcx.target_triple() + unit.kind.short_name(bcx), ) } failure::bail!( "cannot compile `{}` as the target `{}` does not \ support any of the output crate types", unit.pkg, - bcx.target_triple() + unit.kind.short_name(bcx), ); } Ok(ret) @@ -495,7 +495,7 @@ fn compute_metadata<'a, 'cfg>( if !(unit.mode.is_any_test() || unit.mode.is_check()) && (unit.target.is_dylib() || unit.target.is_cdylib() - || (unit.target.is_executable() && bcx.target_triple().starts_with("wasm32-"))) + || (unit.target.is_executable() && unit.kind.short_name(bcx).starts_with("wasm32-"))) && unit.pkg.package_id().source_id().is_path() && __cargo_default_lib_metadata.is_err() { diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index f9cee44a9f3..1600644b55d 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -20,7 +20,7 @@ use super::job_queue::JobQueue; use super::layout::Layout; use super::standard_lib; use super::unit_dependencies::{UnitDep, UnitGraph}; -use super::{BuildContext, Compilation, CompileMode, Executor, FileFlavor, Kind}; +use super::{BuildContext, Compilation, CompileKind, CompileMode, Executor, FileFlavor}; mod compilation_files; use self::compilation_files::CompilationFiles; @@ -79,6 +79,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { config: &'cfg Config, bcx: &'a BuildContext<'a, 'cfg>, unit_dependencies: UnitGraph<'a>, + default_kind: CompileKind, ) -> CargoResult { // Load up the jobserver that we'll use to manage our parallelism. This // is the same as the GNU make implementation of a jobserver, and @@ -105,7 +106,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { Ok(Self { bcx, - compilation: Compilation::new(bcx)?, + compilation: Compilation::new(bcx, default_kind)?, build_script_outputs: Arc::new(Mutex::new(BuildScriptOutputs::default())), fingerprints: HashMap::new(), mtime_cache: HashMap::new(), @@ -303,27 +304,19 @@ impl<'a, 'cfg> Context<'a, 'cfg> { "debug" }; let host_layout = Layout::new(self.bcx.ws, None, dest)?; - let target_layout = match self.bcx.build_config.requested_target.as_ref() { - Some(target) => { - let layout = Layout::new(self.bcx.ws, Some(target), dest)?; - standard_lib::prepare_sysroot(&layout)?; - Some(layout) - } - None => None, - }; + let mut targets = HashMap::new(); + if let CompileKind::Target(target) = self.bcx.build_config.requested_kind { + let layout = Layout::new(self.bcx.ws, Some(target), dest)?; + standard_lib::prepare_sysroot(&layout)?; + targets.insert(target, layout); + } self.primary_packages .extend(units.iter().map(|u| u.pkg.package_id())); self.record_units_requiring_metadata(); - let files = CompilationFiles::new( - units, - host_layout, - target_layout, - export_dir, - self.bcx.ws, - self, - ); + let files = + CompilationFiles::new(units, host_layout, targets, export_dir, self.bcx.ws, self); self.files = Some(files); Ok(()) } @@ -337,7 +330,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { .host .prepare() .chain_err(|| internal("couldn't prepare build directories"))?; - if let Some(ref mut target) = self.files.as_mut().unwrap().target { + for target in self.files.as_mut().unwrap().target.values_mut() { target .prepare() .chain_err(|| internal("couldn't prepare build directories"))?; @@ -346,7 +339,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { self.compilation.host_deps_output = self.files_mut().host.deps().to_path_buf(); let files = self.files.as_ref().unwrap(); - let layout = files.target.as_ref().unwrap_or(&files.host); + let layout = files.layout(self.bcx.build_config.requested_kind); self.compilation.root_output = layout.dest().to_path_buf(); self.compilation.deps_output = layout.deps().to_path_buf(); Ok(()) @@ -450,8 +443,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> { Second unit: {:?}", describe_collision(unit, other_unit, path), suggestion, - crate::version(), self.bcx.host_triple(), self.bcx.target_triple(), - unit, other_unit)) + crate::version(), + self.bcx.host_triple(), + unit.kind.short_name(self.bcx), + unit, + other_unit)) } }; diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index f727087ccfa..8e3e3c4e10f 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -12,7 +12,7 @@ use crate::util::machine_message::{self, Message}; use crate::util::{self, internal, paths, profile}; use super::job::{Freshness, Job, Work}; -use super::{fingerprint, Context, Kind, Unit}; +use super::{fingerprint, CompileKind, Context, Unit}; /// Contains the parsed output of a custom build script. #[derive(Clone, Debug, Hash)] @@ -43,7 +43,7 @@ pub struct BuildOutput { /// This initially starts out as empty. Overridden build scripts get /// inserted during `build_map`. The rest of the entries are added /// immediately after each build script runs. -pub type BuildScriptOutputs = HashMap<(PackageId, Kind), BuildOutput>; +pub type BuildScriptOutputs = HashMap<(PackageId, CompileKind), BuildOutput>; /// Linking information for a `Unit`. /// @@ -63,9 +63,9 @@ pub struct BuildScripts { /// usage here doesn't blow up too much. /// /// For more information, see #2354. - pub to_link: Vec<(PackageId, Kind)>, + pub to_link: Vec<(PackageId, CompileKind)>, /// This is only used while constructing `to_link` to avoid duplicates. - seen_to_link: HashSet<(PackageId, Kind)>, + seen_to_link: HashSet<(PackageId, CompileKind)>, /// Host-only dependencies that have build scripts. /// /// This is the set of transitive dependencies that are host-only @@ -158,13 +158,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes cmd.env("OUT_DIR", &script_out_dir) .env("CARGO_MANIFEST_DIR", unit.pkg.root()) .env("NUM_JOBS", &bcx.jobs().to_string()) - .env( - "TARGET", - &match unit.kind { - Kind::Host => bcx.host_triple(), - Kind::Target => bcx.target_triple(), - }, - ) + .env("TARGET", unit.kind.short_name(bcx)) .env("DEBUG", debug.to_string()) .env("OPT_LEVEL", &unit.profile.opt_level.to_string()) .env( @@ -180,7 +174,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes .env("RUSTDOC", &*bcx.config.rustdoc()?) .inherit_jobserver(&cx.jobserver); - if let Some(ref linker) = bcx.target_config.linker { + if let Some(linker) = &bcx.target_config(unit.kind).linker { cmd.env("RUSTC_LINKER", linker); } @@ -694,7 +688,7 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>, units: &[Unit<'b>]) -> Ca // When adding an entry to 'to_link' we only actually push it on if the // script hasn't seen it yet (e.g., we don't push on duplicates). - fn add_to_link(scripts: &mut BuildScripts, pkg: PackageId, kind: Kind) { + fn add_to_link(scripts: &mut BuildScripts, pkg: PackageId, kind: CompileKind) { if scripts.seen_to_link.insert((pkg, kind)) { scripts.to_link.push((pkg, kind)); } diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index 3db1c9602ef..fc00321e127 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -47,7 +47,7 @@ //! `cargo rustc` extra args | ✓ | ✓ //! CompileMode | ✓ | ✓ //! Target Name | ✓ | ✓ -//! Target Kind (bin/lib/etc.) | ✓ | ✓ +//! Target CompileKind (bin/lib/etc.) | ✓ | ✓ //! Enabled Features | ✓ | ✓ //! Immediate dependency’s hashes | ✓[^1] | ✓ //! Target or Host mode | | ✓ diff --git a/src/cargo/core/compiler/job_queue.rs b/src/cargo/core/compiler/job_queue.rs index ef597aa0071..1bc33185fcd 100644 --- a/src/cargo/core/compiler/job_queue.rs +++ b/src/cargo/core/compiler/job_queue.rs @@ -618,7 +618,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> { Artifact::All => self.timings.unit_finished(id, unlocked), Artifact::Metadata => self.timings.unit_rmeta_finished(id, unlocked), } - if unit.is_std && unit.kind == super::Kind::Target && !cx.bcx.build_config.build_plan { + if unit.is_std && !unit.kind.is_host() && !cx.bcx.build_config.build_plan { // This is a bit of an unusual place to copy files around, and // ideally this would be somewhere like the Work closure // (`link_targets`). The tricky issue is handling rmeta files for diff --git a/src/cargo/core/compiler/layout.rs b/src/cargo/core/compiler/layout.rs index b24c1b58e8f..0647b2e42ec 100644 --- a/src/cargo/core/compiler/layout.rs +++ b/src/cargo/core/compiler/layout.rs @@ -99,6 +99,7 @@ //! When cross-compiling, the layout is the same, except it appears in //! `target/$TRIPLE`. +use crate::core::compiler::CompileTarget; use crate::core::Workspace; use crate::util::paths; use crate::util::{CargoResult, FileLock}; @@ -147,26 +148,15 @@ impl Layout { /// /// `dest` should be the final artifact directory name. Currently either /// "debug" or "release". - pub fn new(ws: &Workspace<'_>, triple: Option<&str>, dest: &str) -> CargoResult { + pub fn new( + ws: &Workspace<'_>, + target: Option, + dest: &str, + ) -> CargoResult { let mut root = ws.target_dir(); - // Flexible target specifications often point at json files, so interpret - // the target triple as a Path and then just use the file stem as the - // component for the directory name in that case. - let triple_path = if let Some(s) = triple { - let p = Path::new(s); - let tp = if p.extension().and_then(|s| s.to_str()) == Some("json") { - Path::new( - p.file_stem() - .ok_or_else(|| failure::format_err!("invalid target"))?, - ) - } else { - p - }; - root.push(tp); - Some(tp) - } else { - None - }; + if let Some(target) = target { + root.push(target.short_name()); + } let dest = root.join(dest); // If the root directory doesn't already exist go ahead and create it // here. Use this opportunity to exclude it from backups as well if the @@ -185,10 +175,14 @@ impl Layout { // Compute the sysroot path for the build-std feature. let build_std = ws.config().cli_unstable().build_std.as_ref(); - let (sysroot, sysroot_libdir) = if let Some(tp) = build_std.and(triple_path) { + let (sysroot, sysroot_libdir) = if let Some(target) = build_std.and(target) { // This uses a leading dot to avoid collision with named profiles. let sysroot = dest.join(".sysroot"); - let sysroot_libdir = sysroot.join("lib").join("rustlib").join(tp).join("lib"); + let sysroot_libdir = sysroot + .join("lib") + .join("rustlib") + .join(target.short_name()) + .join("lib"); (Some(sysroot), Some(sysroot_libdir)) } else { (None, None) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 44bcc0afdf1..542427d9f80 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -2,6 +2,7 @@ mod build_config; mod build_context; mod build_plan; mod compilation; +mod compile_kind; mod context; mod custom_build; mod fingerprint; @@ -25,12 +26,12 @@ use std::sync::Arc; use failure::Error; use lazycell::LazyCell; use log::debug; -use serde::Serialize; pub use self::build_config::{BuildConfig, CompileMode, MessageFormat}; pub use self::build_context::{BuildContext, FileFlavor, TargetConfig, TargetInfo}; use self::build_plan::BuildPlan; pub use self::compilation::{Compilation, Doctest}; +pub use self::compile_kind::{CompileKind, CompileTarget}; pub use self::context::Context; pub use self::custom_build::{BuildOutput, BuildScriptOutputs, BuildScripts}; pub use self::job::Freshness; @@ -50,15 +51,6 @@ use crate::util::paths; use crate::util::{self, machine_message, ProcessBuilder}; use crate::util::{internal, join_paths, profile}; -/// Indicates whether an object is for the host architecture or the target architecture. -/// -/// These will be the same unless cross-compiling. -#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] -pub enum Kind { - Host, - Target, -} - /// A glorified callback for executing calls to rustc. Rather than calling rustc /// directly, we'll use an `Executor`, giving clients an opportunity to intercept /// the build calls. @@ -386,7 +378,7 @@ fn rustc<'a, 'cfg>( rustc: &mut ProcessBuilder, build_script_outputs: &BuildScriptOutputs, current_id: PackageId, - kind: Kind, + kind: CompileKind, ) -> CargoResult<()> { let key = (current_id, kind); if let Some(output) = build_script_outputs.get(&key) { @@ -490,7 +482,7 @@ fn add_plugin_deps( let mut search_path = env::split_paths(&search_path).collect::>(); for &id in build_scripts.plugins.iter() { let output = build_script_outputs - .get(&(id, Kind::Host)) + .get(&(id, CompileKind::Host)) .ok_or_else(|| internal(format!("couldn't find libs for plugin dep {}", id)))?; search_path.append(&mut filter_dynamic_search_path( output.library_paths.iter(), @@ -565,10 +557,8 @@ fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult add_path_args(bcx, unit, &mut rustdoc); add_cap_lints(bcx, unit, &mut rustdoc); - if unit.kind != Kind::Host { - if let Some(ref target) = bcx.build_config.requested_target { - rustdoc.arg("--target").arg(target); - } + if let CompileKind::Target(target) = unit.kind { + rustdoc.arg("--target").arg(target.rustc_target()); } let doc_dir = cx.files().out_dir(unit); @@ -892,16 +882,8 @@ fn build_base_args<'a, 'cfg>( } } - if unit.kind == Kind::Target { - opt( - cmd, - "--target", - "", - bcx.build_config - .requested_target - .as_ref() - .map(|s| s.as_ref()), - ); + if let CompileKind::Target(n) = unit.kind { + cmd.arg("--target").arg(n.rustc_target()); } opt(cmd, "-C", "ar=", bcx.ar(unit.kind).map(|s| s.as_ref())); @@ -942,7 +924,7 @@ fn build_deps_args<'a, 'cfg>( // Be sure that the host path is also listed. This'll ensure that proc macro // dependencies are correctly found (for reexported macros). - if let Kind::Target = unit.kind { + if !unit.kind.is_host() { cmd.arg("-L").arg(&{ let mut deps = OsString::from("dependency="); deps.push(cx.files().host_deps()); @@ -978,8 +960,8 @@ fn build_deps_args<'a, 'cfg>( let mut unstable_opts = false; - if let Some(sysroot) = cx.files().layout(Kind::Target).sysroot() { - if unit.kind == Kind::Target { + if let Some(sysroot) = cx.files().layout(unit.kind).sysroot() { + if !unit.kind.is_host() { cmd.arg("--sysroot").arg(sysroot); } } @@ -1066,19 +1048,6 @@ fn envify(s: &str) -> String { .collect() } -impl Kind { - fn for_target(self, target: &Target) -> Kind { - // Once we start compiling for the `Host` kind we continue doing so, but - // if we are a `Target` kind and then we start compiling for a target - // that needs to be on the host we lift ourselves up to `Host`. - match self { - Kind::Host => Kind::Host, - Kind::Target if target.for_host() => Kind::Host, - Kind::Target => Kind::Target, - } - } -} - struct OutputOptions { /// What format we're emitting from Cargo itself. format: MessageFormat, diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs index 88a8c07af94..fca77282b8b 100644 --- a/src/cargo/core/compiler/standard_lib.rs +++ b/src/cargo/core/compiler/standard_lib.rs @@ -1,7 +1,7 @@ //! Code for building the standard library. use super::layout::Layout; -use crate::core::compiler::{BuildContext, CompileMode, Context, FileFlavor, Kind, Unit}; +use crate::core::compiler::{BuildContext, CompileKind, CompileMode, Context, FileFlavor, Unit}; use crate::core::profiles::UnitFor; use crate::core::resolver::ResolveOpts; use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace}; @@ -113,6 +113,7 @@ pub fn generate_std_roots<'a>( bcx: &BuildContext<'a, '_>, crates: &[String], std_resolve: &'a Resolve, + kind: CompileKind, ) -> CargoResult>> { // Generate the root Units for the standard library. let std_ids = crates @@ -144,13 +145,7 @@ pub fn generate_std_roots<'a>( ); let features = std_resolve.features_sorted(pkg.package_id()); Ok(bcx.units.intern( - pkg, - lib, - profile, - Kind::Target, - mode, - features, - /*is_std*/ true, + pkg, lib, profile, kind, mode, features, /*is_std*/ true, )) }) .collect::>>() @@ -205,7 +200,7 @@ pub fn add_sysroot_artifact<'a>( .filter(|output| output.flavor == FileFlavor::Linkable { rmeta }) .map(|output| &output.path); for path in outputs { - let libdir = cx.files().layout(Kind::Target).sysroot_libdir().unwrap(); + let libdir = cx.files().layout(unit.kind).sysroot_libdir().unwrap(); let dst = libdir.join(path.file_name().unwrap()); paths::link_or_copy(path, dst)?; } diff --git a/src/cargo/core/compiler/timings.rs b/src/cargo/core/compiler/timings.rs index 6098e6dfa2c..1d0191c39c9 100644 --- a/src/cargo/core/compiler/timings.rs +++ b/src/cargo/core/compiler/timings.rs @@ -572,11 +572,7 @@ fn render_rustc_info(bcx: &BuildContext<'_, '_>) -> String { .lines() .next() .expect("rustc version"); - let requested_target = bcx - .build_config - .requested_target - .as_ref() - .map_or("Host", String::as_str); + let requested_target = bcx.build_config.requested_kind.short_name(bcx); format!( "{}
Host: {}
Target: {}", version, bcx.rustc.host, requested_target diff --git a/src/cargo/core/compiler/unit.rs b/src/cargo/core/compiler/unit.rs index 62dc506c0d0..205d351e0a6 100644 --- a/src/cargo/core/compiler/unit.rs +++ b/src/cargo/core/compiler/unit.rs @@ -1,4 +1,4 @@ -use crate::core::compiler::{CompileMode, Kind}; +use crate::core::compiler::{CompileKind, CompileMode}; use crate::core::{profiles::Profile, Package, Target}; use crate::util::hex::short_hash; use std::cell::RefCell; @@ -45,7 +45,7 @@ pub struct UnitInner<'a> { /// cross compiling and using a custom build script, the build script needs to be compiled for /// the host architecture so the host rustc can use it (when compiling to the target /// architecture). - pub kind: Kind, + pub kind: CompileKind, /// The "mode" this unit is being compiled for. See [`CompileMode`] for more details. pub mode: CompileMode, /// The `cfg` features to enable for this unit. @@ -143,7 +143,7 @@ impl<'a> UnitInterner<'a> { pkg: &'a Package, target: &'a Target, profile: Profile, - kind: Kind, + kind: CompileKind, mode: CompileMode, features: Vec<&'a str>, is_std: bool, diff --git a/src/cargo/core/compiler/unit_dependencies.rs b/src/cargo/core/compiler/unit_dependencies.rs index 936adee365a..085c41e97cc 100644 --- a/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/cargo/core/compiler/unit_dependencies.rs @@ -16,7 +16,7 @@ //! graph of `Unit`s, which capture these properties. use crate::core::compiler::Unit; -use crate::core::compiler::{BuildContext, CompileMode, Kind}; +use crate::core::compiler::{BuildContext, CompileKind, CompileMode}; use crate::core::dependency::Kind as DepKind; use crate::core::package::Downloads; use crate::core::profiles::{Profile, UnitFor}; @@ -125,7 +125,7 @@ fn attach_std_deps<'a, 'cfg>( ) { // Attach the standard library as a dependency of every target unit. for (unit, deps) in state.unit_dependencies.iter_mut() { - if unit.kind == Kind::Target && !unit.mode.is_run_custom_build() { + if !unit.kind.is_host() && !unit.mode.is_run_custom_build() { deps.extend(std_roots.iter().map(|unit| UnitDep { unit: *unit, unit_for: UnitFor::new_normal(), @@ -270,13 +270,11 @@ fn compute_deps<'a, 'cfg>( let mode = check_or_build_mode(unit.mode, lib); let dep_unit_for = unit_for.with_for_host(lib.for_host()); - if bcx.config.cli_unstable().dual_proc_macros - && lib.proc_macro() - && unit.kind == Kind::Target - { - let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, Kind::Target, mode)?; + if bcx.config.cli_unstable().dual_proc_macros && lib.proc_macro() && !unit.kind.is_host() { + let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, unit.kind, mode)?; ret.push(unit_dep); - let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, Kind::Host, mode)?; + let unit_dep = + new_unit_dep(state, unit, pkg, lib, dep_unit_for, CompileKind::Host, mode)?; ret.push(unit_dep); } else { let unit_dep = new_unit_dep( @@ -378,7 +376,7 @@ fn compute_deps_custom_build<'a, 'cfg>( // builds. UnitFor::new_build(), // Build scripts always compiled for the host. - Kind::Host, + CompileKind::Host, CompileMode::Build, )?; Ok(vec![unit_dep]) @@ -537,7 +535,7 @@ fn new_unit_dep<'a>( pkg: &'a Package, target: &'a Target, unit_for: UnitFor, - kind: Kind, + kind: CompileKind, mode: CompileMode, ) -> CargoResult> { let profile = state.bcx.profiles.get_profile( @@ -556,7 +554,7 @@ fn new_unit_dep_with_profile<'a>( pkg: &'a Package, target: &'a Target, unit_for: UnitFor, - kind: Kind, + kind: CompileKind, mode: CompileMode, profile: Profile, ) -> CargoResult> { diff --git a/src/cargo/core/interning.rs b/src/cargo/core/interning.rs index f4223f414e4..22935f5ecf9 100644 --- a/src/cargo/core/interning.rs +++ b/src/cargo/core/interning.rs @@ -1,11 +1,12 @@ use serde::{Serialize, Serializer}; - use std::borrow::Borrow; use std::cmp::Ordering; use std::collections::HashSet; +use std::ffi::OsStr; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; +use std::path::Path; use std::ptr; use std::str; use std::sync::Mutex; @@ -35,6 +36,12 @@ impl<'a> From<&'a String> for InternedString { } } +impl From for InternedString { + fn from(item: String) -> Self { + InternedString::new(&item) + } +} + impl PartialEq for InternedString { fn eq(&self, other: &InternedString) -> bool { ptr::eq(self.as_str(), other.as_str()) @@ -74,6 +81,18 @@ impl AsRef for InternedString { } } +impl AsRef for InternedString { + fn as_ref(&self) -> &OsStr { + self.as_str().as_ref() + } +} + +impl AsRef for InternedString { + fn as_ref(&self) -> &Path { + self.as_str().as_ref() + } +} + impl Hash for InternedString { // N.B., we can't implement this as `identity(self).hash(state)`, // because we use this for on-disk fingerprints and so need diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index ac8dd6d72eb..7adc7d2fe07 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -4,7 +4,7 @@ use std::path::Path; use crate::core::compiler::unit_dependencies; use crate::core::compiler::UnitInterner; -use crate::core::compiler::{BuildConfig, BuildContext, CompileMode, Context, Kind}; +use crate::core::compiler::{BuildConfig, BuildContext, CompileKind, CompileMode, Context}; use crate::core::profiles::UnitFor; use crate::core::Workspace; use crate::ops; @@ -73,7 +73,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { // Generate all relevant `Unit` targets for this package for target in pkg.targets() { - for kind in [Kind::Host, Kind::Target].iter() { + for kind in [CompileKind::Host, build_config.requested_kind].iter() { for mode in CompileMode::all_modes() { for unit_for in UnitFor::all_values() { let profile = if mode.is_run_custom_build() { @@ -105,7 +105,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { let unit_dependencies = unit_dependencies::build_unit_dependencies(&bcx, &resolve, None, &units, &[])?; - let mut cx = Context::new(config, &bcx, unit_dependencies)?; + let mut cx = Context::new(config, &bcx, unit_dependencies, build_config.requested_kind)?; cx.prepare_units(None, &units)?; for unit in units.iter() { diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 6c76cb7576c..8233f6ceaeb 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -31,7 +31,7 @@ use std::sync::Arc; use crate::core::compiler::standard_lib; use crate::core::compiler::unit_dependencies::build_unit_dependencies; use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context}; -use crate::core::compiler::{CompileMode, Kind, Unit}; +use crate::core::compiler::{CompileKind, CompileMode, Unit}; use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner}; use crate::core::profiles::{Profiles, UnitFor}; use crate::core::resolver::{Resolve, ResolveOpts}; @@ -294,12 +294,6 @@ pub fn compile_ws<'a>( } } - let default_arch_kind = if build_config.requested_target.is_some() { - Kind::Target - } else { - Kind::Host - }; - let profiles = ws.profiles(); let specs = spec.to_package_id_specs(ws)?; @@ -314,7 +308,7 @@ pub fn compile_ws<'a>( .shell() .warn("-Zbuild-std does not currently fully support --build-plan")?; } - if build_config.requested_target.is_none() { + if build_config.requested_kind.is_host() { // TODO: This should eventually be fixed. Unfortunately it is not // easy to get the host triple in BuildConfig. Consider changing // requested_target to an enum, or some other approach. @@ -390,7 +384,7 @@ pub fn compile_ws<'a>( profiles, &to_builds, filter, - default_arch_kind, + build_config.requested_kind, &resolve_with_overrides, &bcx, )?; @@ -408,7 +402,12 @@ pub fn compile_ws<'a>( crates.push("test".to_string()); } } - standard_lib::generate_std_roots(&bcx, &crates, std_resolve.as_ref().unwrap())? + standard_lib::generate_std_roots( + &bcx, + &crates, + std_resolve.as_ref().unwrap(), + build_config.requested_kind, + )? } else { Vec::new() }; @@ -442,7 +441,7 @@ pub fn compile_ws<'a>( let ret = { let _p = profile::start("compiling"); - let cx = Context::new(config, &bcx, unit_dependencies)?; + let cx = Context::new(config, &bcx, unit_dependencies, build_config.requested_kind)?; cx.compile(&units, export_dir.clone(), exec)? }; @@ -634,7 +633,7 @@ fn generate_targets<'a>( profiles: &Profiles, packages: &[&'a Package], filter: &CompileFilter, - default_arch_kind: Kind, + default_arch_kind: CompileKind, resolve: &'a Resolve, bcx: &BuildContext<'a, '_>, ) -> CargoResult>> { @@ -694,12 +693,7 @@ fn generate_targets<'a>( CompileMode::Bench => CompileMode::Test, _ => target_mode, }; - // Plugins or proc macros should be built for the host. - let kind = if target.for_host() { - Kind::Host - } else { - default_arch_kind - }; + let kind = default_arch_kind.for_target(target); let profile = profiles.get_profile( pkg.package_id(), ws.is_member(pkg), diff --git a/src/cargo/ops/cargo_doc.rs b/src/cargo/ops/cargo_doc.rs index fb9aa7ec49b..c93f586b06f 100644 --- a/src/cargo/ops/cargo_doc.rs +++ b/src/cargo/ops/cargo_doc.rs @@ -1,14 +1,10 @@ -use std::collections::HashMap; -use std::fs; -use std::path::Path; - -use failure::Fail; -use opener; - use crate::core::resolver::ResolveOpts; use crate::core::Workspace; use crate::ops; use crate::util::CargoResult; +use failure::Fail; +use opener; +use std::collections::HashMap; /// Strongly typed options for the `cargo doc` command. #[derive(Debug)] @@ -67,24 +63,19 @@ pub fn doc(ws: &Workspace<'_>, options: &DocOptions<'_>) -> CargoResult<()> { } } - ops::compile(ws, &options.compile_opts)?; + let compilation = ops::compile(ws, &options.compile_opts)?; if options.open_result { let name = match names.first() { Some(s) => s.to_string(), None => return Ok(()), }; - - // Don't bother locking here as if this is getting deleted there's - // nothing we can do about it and otherwise if it's getting overwritten - // then that's also ok! - let mut target_dir = ws.target_dir(); - if let Some(ref triple) = options.compile_opts.build_config.requested_target { - target_dir.push(Path::new(triple).file_stem().unwrap()); - } - let path = target_dir.join("doc").join(&name).join("index.html"); - let path = path.into_path_unlocked(); - if fs::metadata(&path).is_ok() { + let path = compilation + .root_output + .with_file_name("doc") + .join(&name) + .join("index.html"); + if path.exists() { let mut shell = options.compile_opts.config.shell(); shell.status("Opening", path.display())?; if let Err(e) = opener::open(&path) { diff --git a/src/cargo/ops/cargo_fetch.rs b/src/cargo/ops/cargo_fetch.rs index 6ffb62a2313..43835374ab8 100644 --- a/src/cargo/ops/cargo_fetch.rs +++ b/src/cargo/ops/cargo_fetch.rs @@ -1,4 +1,4 @@ -use crate::core::compiler::{BuildConfig, CompileMode, Kind, TargetInfo}; +use crate::core::compiler::{BuildConfig, CompileMode, TargetInfo}; use crate::core::{PackageSet, Resolve, Workspace}; use crate::ops; use crate::util::CargoResult; @@ -23,44 +23,46 @@ pub fn fetch<'a>( let config = ws.config(); let build_config = BuildConfig::new(config, jobs, &options.target, CompileMode::Build)?; let rustc = config.load_global_rustc(Some(ws))?; - let target_info = - TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::Target)?; - { - let mut fetched_packages = HashSet::new(); - let mut deps_to_fetch = ws.members().map(|p| p.package_id()).collect::>(); - let mut to_download = Vec::new(); + let target_info = TargetInfo::new( + config, + build_config.requested_kind, + &rustc, + build_config.requested_kind, + )?; + let mut fetched_packages = HashSet::new(); + let mut deps_to_fetch = ws.members().map(|p| p.package_id()).collect::>(); + let mut to_download = Vec::new(); - while let Some(id) = deps_to_fetch.pop() { - if !fetched_packages.insert(id) { - continue; - } + while let Some(id) = deps_to_fetch.pop() { + if !fetched_packages.insert(id) { + continue; + } - to_download.push(id); - let deps = resolve - .deps(id) - .filter(|&(_id, deps)| { - deps.iter().any(|d| { - // If no target was specified then all dependencies can - // be fetched. - let target = match options.target { - Some(ref t) => t, - None => return true, - }; - // If this dependency is only available for certain - // platforms, make sure we're only fetching it for that - // platform. - let platform = match d.platform() { - Some(p) => p, - None => return true, - }; - platform.matches(target, target_info.cfg()) - }) + to_download.push(id); + let deps = resolve + .deps(id) + .filter(|&(_id, deps)| { + deps.iter().any(|d| { + // If no target was specified then all dependencies can + // be fetched. + let target = match options.target { + Some(ref t) => t, + None => return true, + }; + // If this dependency is only available for certain + // platforms, make sure we're only fetching it for that + // platform. + let platform = match d.platform() { + Some(p) => p, + None => return true, + }; + platform.matches(target, target_info.cfg()) }) - .map(|(id, _deps)| id); - deps_to_fetch.extend(deps); - } - packages.get_many(to_download)?; + }) + .map(|(id, _deps)| id); + deps_to_fetch.extend(deps); } + packages.get_many(to_download)?; Ok((resolve, packages)) } diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 37adde31495..954332a2cbc 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -7,7 +7,7 @@ use failure::{bail, format_err}; use tempfile::Builder as TempFileBuilder; use crate::core::compiler::Freshness; -use crate::core::compiler::{DefaultExecutor, Executor}; +use crate::core::compiler::{CompileKind, DefaultExecutor, Executor}; use crate::core::resolver::ResolveOpts; use crate::core::{Edition, Package, PackageId, PackageIdSpec, Source, SourceId, Workspace}; use crate::ops; @@ -256,12 +256,10 @@ fn install_one( // anything if we're gonna throw it away anyway. let dst = root.join("bin").into_path_unlocked(); let rustc = config.load_global_rustc(Some(&ws))?; - let target = opts - .build_config - .requested_target - .as_ref() - .unwrap_or(&rustc.host) - .clone(); + let target = match &opts.build_config.requested_kind { + CompileKind::Host => rustc.host.as_str(), + CompileKind::Target(target) => target.short_name(), + }; // Helper for --no-track flag to make sure it doesn't overwrite anything. let no_track_duplicates = || -> CargoResult>> { @@ -410,8 +408,8 @@ fn install_one( &successful_bins, vers.map(|s| s.to_string()), opts, - target, - rustc.verbose_version, + &target, + &rustc.verbose_version, ); if let Err(e) = remove_orphaned_bins(&ws, &mut tracker, &duplicates, pkg, &dst) { diff --git a/src/cargo/ops/common_for_install_and_uninstall.rs b/src/cargo/ops/common_for_install_and_uninstall.rs index f61a00d39a8..af79e551311 100644 --- a/src/cargo/ops/common_for_install_and_uninstall.rs +++ b/src/cargo/ops/common_for_install_and_uninstall.rs @@ -283,8 +283,8 @@ impl InstallTracker { bins: &BTreeSet, version_req: Option, opts: &CompileOptions<'_>, - target: String, - rustc: String, + target: &str, + rustc: &str, ) { if self.unstable_upgrade { self.v2 @@ -430,8 +430,8 @@ impl CrateListingV2 { bins: &BTreeSet, version_req: Option, opts: &CompileOptions<'_>, - target: String, - rustc: String, + target: &str, + rustc: &str, ) { // Remove bins from any other packages. for info in &mut self.installs.values_mut() { @@ -456,8 +456,8 @@ impl CrateListingV2 { info.all_features = opts.all_features; info.no_default_features = opts.no_default_features; info.profile = profile_name(opts.build_config.release).to_string(); - info.target = Some(target); - info.rustc = Some(rustc); + info.target = Some(target.to_string()); + info.rustc = Some(rustc.to_string()); } else { self.installs.insert( pkg.package_id(), @@ -468,8 +468,8 @@ impl CrateListingV2 { all_features: opts.all_features, no_default_features: opts.no_default_features, profile: profile_name(opts.build_config.release).to_string(), - target: Some(target), - rustc: Some(rustc), + target: Some(target.to_string()), + rustc: Some(rustc.to_string()), other: BTreeMap::new(), }, ); diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index d79b663aa99..eafdc8dd941 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -9,6 +9,7 @@ use std::sync::Mutex; use log::{debug, info, warn}; use serde::{Deserialize, Serialize}; +use crate::core::InternedString; use crate::util::paths; use crate::util::{self, internal, profile, CargoResult, ProcessBuilder}; @@ -23,7 +24,7 @@ pub struct Rustc { /// Verbose version information (the output of `rustc -vV`) pub verbose_version: String, /// The host triple (arch-platform-OS), this comes from verbose_version. - pub host: String, + pub host: InternedString, cache: Mutex, } @@ -58,7 +59,7 @@ impl Rustc { verbose_version ) })?; - triple.to_string() + InternedString::new(triple) }; Ok(Rustc {