From 593a02f2d78a0b4fce6adbda5551389b8d2f4b7a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Sep 2019 10:53:32 -0700 Subject: [PATCH 1/3] Refactor `Kind` to carry target name in `Target` This commit is an internal refactoring of Cargo's compilation backend to eventually support compiling multiple target simultaneously. The original motivation for this came up in discussion of #7297 and this has long been something I've intended to update Cargo for. Nothing in the backend currently exposes the ability to actually build multiple target simultaneously, but this should have no function change with respect to all current consumers. Eventually we'll need to refactor APIs of how you enter the compilation backend to compile for multiple targets. --- crates/cargo-test-support/src/lib.rs | 2 +- src/cargo/core/compiler/build_config.rs | 5 +- src/cargo/core/compiler/build_context/mod.rs | 88 ++++++++----------- .../compiler/build_context/target_info.rs | 21 ++--- src/cargo/core/compiler/compilation.rs | 23 +++-- .../compiler/context/compilation_files.rs | 28 +++--- src/cargo/core/compiler/context/mod.rs | 41 +++++---- src/cargo/core/compiler/custom_build.rs | 10 +-- src/cargo/core/compiler/mod.rs | 37 ++++---- src/cargo/core/compiler/standard_lib.rs | 3 +- src/cargo/core/compiler/timings.rs | 3 +- src/cargo/core/compiler/unit_dependencies.rs | 9 +- src/cargo/core/interning.rs | 15 +++- src/cargo/ops/cargo_clean.rs | 10 ++- src/cargo/ops/cargo_compile.rs | 13 ++- src/cargo/ops/cargo_fetch.rs | 69 ++++++++------- src/cargo/ops/cargo_install.rs | 4 +- .../ops/common_for_install_and_uninstall.rs | 16 ++-- src/cargo/util/rustc.rs | 5 +- 19 files changed, 203 insertions(+), 199 deletions(-) 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..abede0cb6f2 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -3,6 +3,7 @@ use std::path::Path; use serde::ser; +use crate::core::InternedString; use crate::util::ProcessBuilder; use crate::util::{CargoResult, CargoResultExt, Config, RustfixDiagnosticServer}; @@ -11,7 +12,7 @@ use crate::util::{CargoResult, CargoResultExt, Config, RustfixDiagnosticServer}; pub struct BuildConfig { /// The target arch triple. /// Default: host arch. - pub requested_target: Option, + pub requested_target: Option, /// Number of rustc jobs to run in parallel. pub jobs: u32, /// `true` if we are building for release. @@ -91,7 +92,7 @@ impl BuildConfig { let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32); Ok(BuildConfig { - requested_target: target, + requested_target: target.as_ref().map(|s| s.into()), 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..e43721e1742 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -1,17 +1,14 @@ -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::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}; @@ -36,11 +33,11 @@ pub struct BuildContext<'a, 'cfg> { /// Information about the compiler. pub rustc: Rustc, /// Build information for the host arch. - pub host_config: TargetConfig, + host_config: TargetConfig, /// Build information for the target. - pub target_config: TargetConfig, - pub target_info: TargetInfo, - pub host_info: TargetInfo, + target_config: HashMap, + target_info: HashMap, + host_info: TargetInfo, pub units: &'a UnitInterner<'a>, } @@ -57,19 +54,16 @@ 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_target, &rustc, Kind::Host)?; + let mut target_config = HashMap::new(); + let mut target_info = HashMap::new(); + if let Some(target) = build_config.requested_target { + target_config.insert(target, TargetConfig::new(config, &target)?); + target_info.insert( + target, + TargetInfo::new(config, Some(target), &rustc, Kind::Target(target))?, + ); + } Ok(BuildContext { ws, @@ -96,11 +90,8 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { 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 = self.target_triple(kind); + platform.matches(&name, self.cfg(kind)) } /// Gets the user-specified linker for a particular host or target. @@ -115,11 +106,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { /// 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() + self.info(kind).cfg() } /// Gets the host architecture triple. @@ -128,23 +115,23 @@ 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 host_triple(&self) -> InternedString { + 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()) + /// Returns the target triple associated with a `Kind` + pub fn target_triple(&self, kind: Kind) -> InternedString { + match kind { + Kind::Host => self.host_triple(), + Kind::Target(name) => name, + } } /// Gets the target configuration for a particular host or target. - fn target_config(&self, kind: Kind) -> &TargetConfig { + pub fn target_config(&self, kind: Kind) -> &TargetConfig { match kind { Kind::Host => &self.host_config, - Kind::Target => &self.target_config, + Kind::Target(s) => &self.target_config[&s], } } @@ -165,10 +152,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: Kind) -> &TargetInfo { match kind { Kind::Host => &self.host_info, - Kind::Target => &self.target_info, + Kind::Target(s) => &self.target_info[&s], } } @@ -181,10 +168,7 @@ 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), - } + 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..26ea0aa81af 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use std::str::{self, FromStr}; use crate::core::compiler::Kind; +use crate::core::InternedString; use crate::core::TargetKind; use crate::util::{CargoResult, CargoResultExt, Config, ProcessBuilder, Rustc}; use cargo_platform::{Cfg, CfgExpr}; @@ -80,7 +81,7 @@ impl FileType { impl TargetInfo { pub fn new( config: &Config, - requested_target: &Option, + requested_target: Option, rustc: &Rustc, kind: Kind, ) -> CargoResult { @@ -101,12 +102,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 Kind::Target(target) = kind { + process.arg("--target").arg(target); } let crate_type_process = process.clone(); @@ -148,10 +145,10 @@ impl TargetInfo { } rustlib } - Kind::Target => { + Kind::Target(target) => { rustlib.push("lib"); rustlib.push("rustlib"); - rustlib.push(target_triple); + rustlib.push(target); rustlib.push("lib"); rustlib } @@ -381,7 +378,7 @@ 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_target: Option, host_triple: &str, target_cfg: Option<&[Cfg]>, kind: Kind, @@ -407,9 +404,7 @@ fn env_args( // 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 compiling_with_target && 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. diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 2f0b190eb19..ab28cee6b44 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::Kind; 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: Kind, + ) -> 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(Kind::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: bcx.target_triple(default_kind).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: Kind, +) -> CargoResult)>> { + let target = bcx.target_triple(kind); // try target.{}.runner let key = format!("target.{}.runner", target); @@ -303,7 +310,7 @@ fn target_runner(bcx: &BuildContext<'_, '_>) -> CargoResult { /// 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>, @@ -122,7 +122,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { pub fn layout(&self, kind: Kind) -> &Layout { match kind { Kind::Host => &self.host, - Kind::Target => self.target.as_ref().unwrap_or(&self.host), + Kind::Target(name) => self.target.get(&name).unwrap_or(&self.host), } } @@ -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(), + &bcx.target_triple(unit.kind), + )?; 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() + bcx.target_triple(unit.kind), ) } failure::bail!( "cannot compile `{}` as the target `{}` does not \ support any of the output crate types", unit.pkg, - bcx.target_triple() + bcx.target_triple(unit.kind), ); } 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() && bcx.target_triple(unit.kind).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..e6999209f6e 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -79,6 +79,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { config: &'cfg Config, bcx: &'a BuildContext<'a, 'cfg>, unit_dependencies: UnitGraph<'a>, + default_kind: Kind, ) -> 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 Some(target) = self.bcx.build_config.requested_target { + 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,10 @@ 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 = match self.bcx.build_config.requested_target { + Some(target) => &files.target[&target], + None => &files.host, + }; self.compilation.root_output = layout.dest().to_path_buf(); self.compilation.deps_output = layout.deps().to_path_buf(); Ok(()) @@ -450,8 +446,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(), + self.bcx.target_triple(unit.kind), + unit, + other_unit)) } }; diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index f727087ccfa..3c883d2a16f 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -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", bcx.target_triple(unit.kind)) .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); } diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 44bcc0afdf1..afd847f343f 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -43,7 +43,7 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{Lto, PanicStrategy, Profile}; use crate::core::Feature; -use crate::core::{PackageId, Target}; +use crate::core::{InternedString, PackageId, Target}; use crate::util::errors::{CargoResult, CargoResultExt, Internal, ProcessError}; use crate::util::machine_message::Message; use crate::util::paths; @@ -56,7 +56,16 @@ use crate::util::{internal, join_paths, profile}; #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] pub enum Kind { Host, - Target, + Target(InternedString), +} + +impl Kind { + pub fn is_host(&self) -> bool { + match self { + Kind::Host => true, + _ => false, + } + } } /// A glorified callback for executing calls to rustc. Rather than calling rustc @@ -565,10 +574,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 Kind::Target(target) = unit.kind { + rustdoc.arg("--target").arg(target); } let doc_dir = cx.files().out_dir(unit); @@ -892,16 +899,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 Kind::Target(n) = unit.kind { + cmd.arg("--target").arg(n); } opt(cmd, "-C", "ar=", bcx.ar(unit.kind).map(|s| s.as_ref())); @@ -942,7 +941,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 let Kind::Target(_) = unit.kind { cmd.arg("-L").arg(&{ let mut deps = OsString::from("dependency="); deps.push(cx.files().host_deps()); @@ -1073,8 +1072,8 @@ impl Kind { // 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, + Kind::Target(_) if target.for_host() => Kind::Host, + Kind::Target(n) => Kind::Target(n), } } } diff --git a/src/cargo/core/compiler/standard_lib.rs b/src/cargo/core/compiler/standard_lib.rs index 88a8c07af94..c2a415479ab 100644 --- a/src/cargo/core/compiler/standard_lib.rs +++ b/src/cargo/core/compiler/standard_lib.rs @@ -113,6 +113,7 @@ pub fn generate_std_roots<'a>( bcx: &BuildContext<'a, '_>, crates: &[String], std_resolve: &'a Resolve, + kind: Kind, ) -> CargoResult>> { // Generate the root Units for the standard library. let std_ids = crates @@ -147,7 +148,7 @@ pub fn generate_std_roots<'a>( pkg, lib, profile, - Kind::Target, + kind, mode, features, /*is_std*/ true, diff --git a/src/cargo/core/compiler/timings.rs b/src/cargo/core/compiler/timings.rs index 6098e6dfa2c..d103a42394c 100644 --- a/src/cargo/core/compiler/timings.rs +++ b/src/cargo/core/compiler/timings.rs @@ -576,7 +576,8 @@ fn render_rustc_info(bcx: &BuildContext<'_, '_>) -> String { .build_config .requested_target .as_ref() - .map_or("Host", String::as_str); + .map(|s| s.as_str()) + .unwrap_or("Host"); format!( "{}
Host: {}
Target: {}", version, bcx.rustc.host, requested_target diff --git a/src/cargo/core/compiler/unit_dependencies.rs b/src/cargo/core/compiler/unit_dependencies.rs index 936adee365a..136672662fb 100644 --- a/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/cargo/core/compiler/unit_dependencies.rs @@ -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,11 +270,8 @@ 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)?; ret.push(unit_dep); diff --git a/src/cargo/core/interning.rs b/src/cargo/core/interning.rs index f4223f414e4..e0aa8c8922a 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; @@ -74,6 +75,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..3e7ff13e0f8 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -66,6 +66,11 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { )?; let mut units = Vec::new(); + let mut kinds = vec![Kind::Host]; + if let Some(target) = build_config.requested_target { + kinds.push(Kind::Target(target)); + } + for spec in opts.spec.iter() { // Translate the spec to a Package let pkgid = resolve.query(spec)?; @@ -73,7 +78,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 kinds.iter() { for mode in CompileMode::all_modes() { for unit_for in UnitFor::all_values() { let profile = if mode.is_run_custom_build() { @@ -105,7 +110,8 @@ 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 default_kind = kinds.last().cloned().unwrap(); + let mut cx = Context::new(config, &bcx, unit_dependencies, default_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..4ce435e9e7e 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -294,8 +294,8 @@ pub fn compile_ws<'a>( } } - let default_arch_kind = if build_config.requested_target.is_some() { - Kind::Target + let default_arch_kind = if let Some(s) = build_config.requested_target { + Kind::Target(s) } else { Kind::Host }; @@ -408,7 +408,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(), + default_arch_kind, + )? } else { Vec::new() }; @@ -442,7 +447,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, default_arch_kind)?; cx.compile(&units, export_dir.clone(), exec)? }; diff --git a/src/cargo/ops/cargo_fetch.rs b/src/cargo/ops/cargo_fetch.rs index 6ffb62a2313..3ce5a91c0c8 100644 --- a/src/cargo/ops/cargo_fetch.rs +++ b/src/cargo/ops/cargo_fetch.rs @@ -23,44 +23,45 @@ 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 kind = match build_config.requested_target { + Some(t) => Kind::Target(t), + None => Kind::Host, + }; + let target_info = TargetInfo::new(config, build_config.requested_target, &rustc, 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..4ea5023b2bd 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -410,8 +410,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 { From ef425b77e2026a648dc274e2fad83ac04b48d6b3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Sep 2019 08:14:20 -0700 Subject: [PATCH 2/3] Refactor how compile targets are handled Rename `Kind` to `CompileKind` to reflect that it's intended for compilation. Additionally change the `Target` variant to have a newtype `CompileTarget` instead of just being a raw string. This new `CompileTarget` type has a fallible constructor and handles custom json target files internally. Two accessors are available for `CompileTarget`, one is `rustc_target()` which goes straight to rustc and everything else uses `short_name()` which is the raw target or file stem for json files. The `short_name` is used everywhere in Cargo for all purposes like configuration, env vars, target directory naming, etc. --- src/cargo/core/compiler/build_config.rs | 55 ++++-------- src/cargo/core/compiler/build_context/mod.rs | 59 ++++++------ .../compiler/build_context/target_info.rs | 47 ++++------ src/cargo/core/compiler/build_plan.rs | 4 +- src/cargo/core/compiler/compilation.rs | 12 +-- src/cargo/core/compiler/compile_kind.rs | 90 +++++++++++++++++++ .../compiler/context/compilation_files.rs | 26 +++--- src/cargo/core/compiler/context/mod.rs | 15 ++-- src/cargo/core/compiler/custom_build.rs | 12 +-- src/cargo/core/compiler/fingerprint.rs | 2 +- src/cargo/core/compiler/job_queue.rs | 2 +- src/cargo/core/compiler/layout.rs | 36 ++++---- src/cargo/core/compiler/mod.rs | 54 +++-------- src/cargo/core/compiler/standard_lib.rs | 14 +-- src/cargo/core/compiler/timings.rs | 7 +- src/cargo/core/compiler/unit.rs | 6 +- src/cargo/core/compiler/unit_dependencies.rs | 11 +-- src/cargo/core/interning.rs | 6 ++ src/cargo/ops/cargo_clean.rs | 12 +-- src/cargo/ops/cargo_compile.rs | 25 ++---- src/cargo/ops/cargo_doc.rs | 29 +++--- src/cargo/ops/cargo_fetch.rs | 13 +-- src/cargo/ops/cargo_install.rs | 12 ++- 23 files changed, 273 insertions(+), 276 deletions(-) create mode 100644 src/cargo/core/compiler/compile_kind.rs diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index abede0cb6f2..d39294660ce 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -1,18 +1,16 @@ use std::cell::RefCell; -use std::path::Path; use serde::ser; -use crate::core::InternedString; +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. @@ -47,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") @@ -92,7 +75,7 @@ impl BuildConfig { let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32); Ok(BuildConfig { - requested_target: target.as_ref().map(|s| s.into()), + 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 e43721e1742..1b048a38215 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -1,5 +1,6 @@ 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, InternedString, Workspace}; use crate::core::{PackageId, PackageSet}; @@ -35,8 +36,8 @@ pub struct BuildContext<'a, 'cfg> { /// Build information for the host arch. host_config: TargetConfig, /// Build information for the target. - target_config: HashMap, - target_info: HashMap, + target_config: HashMap, + target_info: HashMap, host_info: TargetInfo, pub units: &'a UnitInterner<'a>, } @@ -54,14 +55,24 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { let rustc = config.load_global_rustc(Some(ws))?; let host_config = TargetConfig::new(config, &rustc.host)?; - let host_info = TargetInfo::new(config, build_config.requested_target, &rustc, Kind::Host)?; + 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 Some(target) = build_config.requested_target { - target_config.insert(target, TargetConfig::new(config, &target)?); + 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, Some(target), &rustc, Kind::Target(target))?, + TargetInfo::new( + config, + build_config.requested_kind, + &rustc, + CompileKind::Target(target), + )?, ); } @@ -82,30 +93,30 @@ 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 = self.target_triple(kind); + 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] { + pub fn cfg(&self, kind: CompileKind) -> &[Cfg] { self.info(kind).cfg() } @@ -119,19 +130,11 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { self.rustc.host } - /// Returns the target triple associated with a `Kind` - pub fn target_triple(&self, kind: Kind) -> InternedString { - match kind { - Kind::Host => self.host_triple(), - Kind::Target(name) => name, - } - } - /// Gets the target configuration for a particular host or target. - pub fn target_config(&self, kind: Kind) -> &TargetConfig { + pub fn target_config(&self, kind: CompileKind) -> &TargetConfig { match kind { - Kind::Host => &self.host_config, - Kind::Target(s) => &self.target_config[&s], + CompileKind::Host => &self.host_config, + CompileKind::Target(s) => &self.target_config[&s], } } @@ -152,10 +155,10 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { pkg.source_id().is_path() || self.config.extra_verbose() } - pub fn info(&self, kind: Kind) -> &TargetInfo { + pub fn info(&self, kind: CompileKind) -> &TargetInfo { match kind { - Kind::Host => &self.host_info, - Kind::Target(s) => &self.target_info[&s], + CompileKind::Host => &self.host_info, + CompileKind::Target(s) => &self.target_info[&s], } } @@ -167,7 +170,7 @@ 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> { + 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 26ea0aa81af..fbef06e1c4f 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -4,8 +4,7 @@ use std::env; use std::path::PathBuf; use std::str::{self, FromStr}; -use crate::core::compiler::Kind; -use crate::core::InternedString; +use crate::core::compiler::CompileKind; use crate::core::TargetKind; use crate::util::{CargoResult, CargoResultExt, Config, ProcessBuilder, Rustc}; use cargo_platform::{Cfg, CfgExpr}; @@ -37,7 +36,7 @@ pub struct TargetInfo { pub rustdocflags: Vec, } -/// Kind of each file generated by a Unit, part of `FileType`. +/// CompileKind of each file generated by a Unit, part of `FileType`. #[derive(Clone, PartialEq, Eq, Debug)] pub enum FileFlavor { /// Not a special file type. @@ -81,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("-") @@ -102,8 +94,8 @@ impl TargetInfo { .args(&rustflags) .env_remove("RUSTC_LOG"); - if let Kind::Target(target) = kind { - process.arg("--target").arg(target); + if let CompileKind::Target(target) = kind { + process.arg("--target").arg(target.rustc_target()); } let crate_type_process = process.clone(); @@ -137,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 { @@ -145,10 +137,10 @@ impl TargetInfo { } rustlib } - Kind::Target(target) => { + CompileKind::Target(target) => { rustlib.push("lib"); rustlib.push("rustlib"); - rustlib.push(target); + rustlib.push(target.short_name()); rustlib.push("lib"); rustlib } @@ -172,7 +164,7 @@ impl TargetInfo { // information rustflags: env_args( config, - requested_target, + requested_kind, &rustc.host, Some(&cfg), kind, @@ -180,7 +172,7 @@ impl TargetInfo { )?, rustdocflags: env_args( config, - requested_target, + requested_kind, &rustc.host, Some(&cfg), kind, @@ -378,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 @@ -403,8 +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(); - if compiling_with_target && kind.is_host() { + 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. @@ -428,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 ab28cee6b44..86afe35ac34 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -7,7 +7,7 @@ use cargo_platform::CfgExpr; use semver::Version; use super::BuildContext; -use crate::core::compiler::Kind; +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}; @@ -81,7 +81,7 @@ pub struct Compilation<'cfg> { impl<'cfg> Compilation<'cfg> { pub fn new<'a>( bcx: &BuildContext<'a, 'cfg>, - default_kind: Kind, + default_kind: CompileKind, ) -> CargoResult> { let mut rustc = bcx.rustc.process(); @@ -101,7 +101,7 @@ impl<'cfg> Compilation<'cfg> { root_output: PathBuf::from("/"), deps_output: PathBuf::from("/"), host_deps_output: PathBuf::from("/"), - host_dylib_path: bcx.info(Kind::Host).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(), @@ -113,7 +113,7 @@ impl<'cfg> Compilation<'cfg> { rustc_process: rustc, primary_unit_rustc_process, host: bcx.host_triple().to_string(), - target: bcx.target_triple(default_kind).to_string(), + 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)?, }) @@ -295,9 +295,9 @@ fn pre_version_component(v: &Version) -> String { fn target_runner( bcx: &BuildContext<'_, '_>, - kind: Kind, + kind: CompileKind, ) -> CargoResult)>> { - let target = bcx.target_triple(kind); + let target = kind.short_name(bcx); // try target.{}.runner let key = format!("target.{}.runner", target); diff --git a/src/cargo/core/compiler/compile_kind.rs b/src/cargo/core/compiler/compile_kind.rs new file mode 100644 index 00000000000..46f1c680bf8 --- /dev/null +++ b/src/cargo/core/compiler/compile_kind.rs @@ -0,0 +1,90 @@ +use crate::core::compiler::BuildContext; +use crate::core::{InternedString, Target}; +use crate::util::errors::{CargoResult, CargoResultExt}; +use serde::Serialize; +use std::path::Path; + +/// Indicates whether an object is for the host architcture or the target architecture. +/// +/// These will be the same unless cross-compiling. +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] +pub enum CompileKind { + Host, + Target(CompileTarget), +} + +impl CompileKind { + pub fn is_host(&self) -> 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(), + } + } +} + +#[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() }) + } + + pub fn rustc_target(&self) -> &str { + &self.name + } + + 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 0af90c6683e..36cd3023b53 100644 --- a/src/cargo/core/compiler/context/compilation_files.rs +++ b/src/cargo/core/compiler/context/compilation_files.rs @@ -8,9 +8,9 @@ use std::sync::Arc; use lazycell::LazyCell; use log::info; -use super::{BuildContext, Context, FileFlavor, Kind, Layout}; -use crate::core::compiler::{CompileMode, Unit}; -use crate::core::{InternedString, TargetKind, Workspace}; +use super::{BuildContext, CompileKind, Context, FileFlavor, Layout}; +use crate::core::compiler::{CompileMode, CompileTarget, Unit}; +use crate::core::{TargetKind, Workspace}; use crate::util::{self, CargoResult}; /// The `Metadata` is a hash used to make unique file names for each unit in a build. @@ -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: HashMap, + 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: HashMap, + 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(name) => self.target.get(&name).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 @@ -358,7 +358,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { crate_type, flavor, unit.target.kind(), - &bcx.target_triple(unit.kind), + unit.kind.short_name(bcx), )?; match file_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), + 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), + 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(unit.kind).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 e6999209f6e..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,7 +79,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { config: &'cfg Config, bcx: &'a BuildContext<'a, 'cfg>, unit_dependencies: UnitGraph<'a>, - default_kind: Kind, + 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 @@ -305,8 +305,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { }; let host_layout = Layout::new(self.bcx.ws, None, dest)?; let mut targets = HashMap::new(); - if let Some(target) = self.bcx.build_config.requested_target { - let layout = Layout::new(self.bcx.ws, Some(&target), dest)?); + 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); } @@ -339,10 +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 = match self.bcx.build_config.requested_target { - Some(target) => &files.target[&target], - None => &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(()) @@ -448,7 +445,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { suggestion, crate::version(), self.bcx.host_triple(), - self.bcx.target_triple(unit.kind), + 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 3c883d2a16f..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,7 +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", bcx.target_triple(unit.kind)) + .env("TARGET", unit.kind.short_name(bcx)) .env("DEBUG", debug.to_string()) .env("OPT_LEVEL", &unit.profile.opt_level.to_string()) .env( @@ -688,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 afd847f343f..1e1d9cc1c09 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; @@ -43,31 +44,13 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{Lto, PanicStrategy, Profile}; use crate::core::Feature; -use crate::core::{InternedString, PackageId, Target}; +use crate::core::{PackageId, Target}; use crate::util::errors::{CargoResult, CargoResultExt, Internal, ProcessError}; use crate::util::machine_message::Message; 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(InternedString), -} - -impl Kind { - pub fn is_host(&self) -> bool { - match self { - Kind::Host => true, - _ => false, - } - } -} - /// 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. @@ -395,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) { @@ -499,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(), @@ -574,8 +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 let Kind::Target(target) = unit.kind { - 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); @@ -899,8 +882,8 @@ fn build_base_args<'a, 'cfg>( } } - if let Kind::Target(n) = unit.kind { - cmd.arg("--target").arg(n); + 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())); @@ -941,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 let CompileKind::Target(_) = unit.kind { cmd.arg("-L").arg(&{ let mut deps = OsString::from("dependency="); deps.push(cx.files().host_deps()); @@ -977,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); } } @@ -1065,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(n) => Kind::Target(n), - } - } -} - 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 c2a415479ab..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,7 +113,7 @@ pub fn generate_std_roots<'a>( bcx: &BuildContext<'a, '_>, crates: &[String], std_resolve: &'a Resolve, - kind: Kind, + kind: CompileKind, ) -> CargoResult>> { // Generate the root Units for the standard library. let std_ids = crates @@ -145,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, - mode, - features, - /*is_std*/ true, + pkg, lib, profile, kind, mode, features, /*is_std*/ true, )) }) .collect::>>() @@ -206,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 d103a42394c..1d0191c39c9 100644 --- a/src/cargo/core/compiler/timings.rs +++ b/src/cargo/core/compiler/timings.rs @@ -572,12 +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(|s| s.as_str()) - .unwrap_or("Host"); + 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 136672662fb..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}; @@ -273,7 +273,8 @@ fn compute_deps<'a, 'cfg>( 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( @@ -375,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]) @@ -534,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( @@ -553,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 e0aa8c8922a..22935f5ecf9 100644 --- a/src/cargo/core/interning.rs +++ b/src/cargo/core/interning.rs @@ -36,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()) diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 3e7ff13e0f8..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; @@ -66,11 +66,6 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { )?; let mut units = Vec::new(); - let mut kinds = vec![Kind::Host]; - if let Some(target) = build_config.requested_target { - kinds.push(Kind::Target(target)); - } - for spec in opts.spec.iter() { // Translate the spec to a Package let pkgid = resolve.query(spec)?; @@ -78,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 kinds.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() { @@ -110,8 +105,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { let unit_dependencies = unit_dependencies::build_unit_dependencies(&bcx, &resolve, None, &units, &[])?; - let default_kind = kinds.last().cloned().unwrap(); - let mut cx = Context::new(config, &bcx, unit_dependencies, default_kind)?; + 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 4ce435e9e7e..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 let Some(s) = build_config.requested_target { - Kind::Target(s) - } 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, )?; @@ -412,7 +406,7 @@ pub fn compile_ws<'a>( &bcx, &crates, std_resolve.as_ref().unwrap(), - default_arch_kind, + build_config.requested_kind, )? } else { Vec::new() @@ -447,7 +441,7 @@ pub fn compile_ws<'a>( let ret = { let _p = profile::start("compiling"); - let cx = Context::new(config, &bcx, unit_dependencies, default_arch_kind)?; + let cx = Context::new(config, &bcx, unit_dependencies, build_config.requested_kind)?; cx.compile(&units, export_dir.clone(), exec)? }; @@ -639,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>> { @@ -699,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 3ce5a91c0c8..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,11 +23,12 @@ 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 kind = match build_config.requested_target { - Some(t) => Kind::Target(t), - None => Kind::Host, - }; - let target_info = TargetInfo::new(config, build_config.requested_target, &rustc, kind)?; + 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(); diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 4ea5023b2bd..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>> { From f745ca70ca880f7a4220f767f392c657464e0537 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 26 Sep 2019 08:13:32 -0700 Subject: [PATCH 3/3] Address review about doc blocks --- src/cargo/core/compiler/build_context/mod.rs | 19 ++++++--- .../compiler/build_context/target_info.rs | 2 +- src/cargo/core/compiler/compile_kind.rs | 42 ++++++++++++++++++- src/cargo/core/compiler/mod.rs | 2 +- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 1b048a38215..c21938bbb3f 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -31,15 +31,24 @@ pub struct BuildContext<'a, 'cfg> { pub extra_compiler_args: HashMap, Vec>, pub packages: &'a PackageSet<'cfg>, - /// Information about the compiler. + /// 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 arch. + + /// 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, - /// Build information for the target. + 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, - host_info: TargetInfo, - pub units: &'a UnitInterner<'a>, } impl<'a, 'cfg> BuildContext<'a, 'cfg> { diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index fbef06e1c4f..64b7f079ba2 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -36,7 +36,7 @@ pub struct TargetInfo { pub rustdocflags: Vec, } -/// CompileKind of each file generated by a Unit, part of `FileType`. +/// Kind of each file generated by a Unit, part of `FileType`. #[derive(Clone, PartialEq, Eq, Debug)] pub enum FileFlavor { /// Not a special file type. diff --git a/src/cargo/core/compiler/compile_kind.rs b/src/cargo/core/compiler/compile_kind.rs index 46f1c680bf8..dbfdbbdef67 100644 --- a/src/cargo/core/compiler/compile_kind.rs +++ b/src/cargo/core/compiler/compile_kind.rs @@ -4,12 +4,21 @@ use crate::util::errors::{CargoResult, CargoResultExt}; use serde::Serialize; use std::path::Path; -/// Indicates whether an object is for the host architcture or the target architecture. +/// Indicator for how a unit is being compiled. /// -/// These will be the same unless cross-compiling. +/// This is used primarily for organizing cross compilations vs host +/// compilations, where cross compilations happen at the request of `--target` +/// and host compilations happen for things like build scripts and procedural +/// macros. #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] pub enum CompileKind { + /// Attached to a unit that is compiled for the "host" system or otherwise + /// is compiled without a `--target` flag. This is used for procedural + /// macros and build scripts, or if the `--target` flag isn't passed. Host, + + /// Attached to a unit to be compiled for a particular target. This is used + /// for units when the `--target` flag is passed. Target(CompileTarget), } @@ -42,6 +51,23 @@ impl CompileKind { } } +/// 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, @@ -71,10 +97,22 @@ impl CompileTarget { 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 diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 1e1d9cc1c09..542427d9f80 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -924,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 CompileKind::Target(_) = unit.kind { + if !unit.kind.is_host() { cmd.arg("-L").arg(&{ let mut deps = OsString::from("dependency="); deps.push(cx.files().host_deps());