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 | 71 +++++++-------- src/cargo/ops/cargo_install.rs | 4 +- .../ops/common_for_install_and_uninstall.rs | 16 ++-- src/cargo/util/rustc.rs | 5 +- 19 files changed, 204 insertions(+), 200 deletions(-) diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index 0ee88e8d4..6aa37a4f3 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 958f8c1ca..abede0cb6 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 7333b08c6..e43721e17 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 2a4f5545b..26ea0aa81 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 2f0b190eb..ab28cee6b 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 f9cee44a9..e6999209f 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 f727087cc..3c883d2a1 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 44bcc0afd..afd847f34 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 88a8c07af..c2a415479 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 6098e6dfa..d103a4239 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 936adee36..136672662 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 f4223f414..e0aa8c892 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 ac8dd6d72..3e7ff13e0 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 6c76cb757..4ce435e9e 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 6ffb62a23..3ce5a91c0 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; - } - - 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); + while let Some(id) = deps_to_fetch.pop() { + if !fetched_packages.insert(id) { + continue; } - packages.get_many(to_download)?; + + 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)?; Ok((resolve, packages)) } diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 37adde314..4ea5023b2 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 f61a00d39..af79e5513 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 d79b663aa..eafdc8dd9 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 abede0cb6..d39294660 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 e43721e17..1b048a382 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 26ea0aa81..fbef06e1c 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 cfdd1a015..d40d4a877 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 ab28cee6b..86afe35ac 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 000000000..46f1c680b --- /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 0af90c668..36cd3023b 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 e6999209f..1600644b5 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 3c883d2a1..8e3e3c4e1 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 3db1c9602..fc00321e1 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 ef597aa00..1bc33185f 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 b24c1b58e..0647b2e42 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 afd847f34..1e1d9cc1c 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 c2a415479..fca77282b 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 d103a4239..1d0191c39 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 62dc506c0..205d351e0 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 136672662..085c41e97 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 e0aa8c892..22935f5ec 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 3e7ff13e0..7adc7d2fe 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 4ce435e9e..8233f6cea 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 fb9aa7ec4..c93f586b0 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 3ce5a91c0..43835374a 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 4ea5023b2..954332a2c 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 1b048a382..c21938bbb 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 fbef06e1c..64b7f079b 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 46f1c680b..dbfdbbdef 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 1e1d9cc1c..542427d9f 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());