diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 7eab9dea45f..d116b2e2e09 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -15,6 +15,8 @@ use crate::util::{profile, Cfg, Config, Rustc}; mod target_info; pub use self::target_info::{FileFlavor, TargetInfo}; +pub const HOST_SANDBOX_TARGET: &str = "wasm32-unknown-unknown"; + /// The build context, containing all information about a build task. /// /// It is intended that this is mostly static information. Stuff that mutates @@ -38,10 +40,13 @@ pub struct BuildContext<'a, 'cfg> { pub rustc: Rustc, /// Build information for the host arch. pub host_config: TargetConfig, + /// Build information for the host sandbox arch (wasm). + pub host_sandbox_config: TargetConfig, /// Build information for the target. pub target_config: TargetConfig, pub target_info: TargetInfo, pub host_info: TargetInfo, + pub host_sandbox_info: TargetInfo, pub units: &'a UnitInterner<'a>, } @@ -59,18 +64,21 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { let rustc = config.load_global_rustc(Some(ws))?; let host_config = TargetConfig::new(config, &rustc.host)?; + let host_sandbox_config = TargetConfig::new(config, HOST_SANDBOX_TARGET)?; 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 (host_info, host_sandbox_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 host_sandbox_info = + TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::HostSandbox)?; let target_info = TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::Target)?; - (host_info, target_info) + (host_info, host_sandbox_info, target_info) }; Ok(BuildContext { @@ -82,7 +90,9 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { target_config, target_info, host_config, + host_sandbox_config, host_info, + host_sandbox_info, build_config, profiles, extra_compiler_args, @@ -111,6 +121,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { }; let (name, info) = match kind { Kind::Host => (self.host_triple(), &self.host_info), + Kind::HostSandbox => (self.host_sandbox_triple(), &self.host_sandbox_info), Kind::Target => (self.target_triple(), &self.target_info), }; platform.matches(name, info.cfg()) @@ -130,6 +141,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { pub fn cfg(&self, kind: Kind) -> &[Cfg] { let info = match kind { Kind::Host => &self.host_info, + Kind::HostSandbox => &self.host_sandbox_info, Kind::Target => &self.target_info, }; info.cfg() @@ -145,6 +157,10 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { &self.rustc.host } + pub fn host_sandbox_triple(&self) -> &str { + HOST_SANDBOX_TARGET + } + pub fn target_triple(&self) -> &str { self.build_config .requested_target @@ -157,6 +173,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { fn target_config(&self, kind: Kind) -> &TargetConfig { match kind { Kind::Host => &self.host_config, + Kind::HostSandbox => &self.host_sandbox_config, Kind::Target => &self.target_config, } } @@ -181,6 +198,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { fn info(&self, kind: Kind) -> &TargetInfo { match kind { Kind::Host => &self.host_info, + Kind::HostSandbox => &self.host_sandbox_info, Kind::Target => &self.target_info, } } @@ -196,6 +214,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { pub fn script_override(&self, lib_name: &str, kind: Kind) -> Option<&BuildOutput> { match kind { Kind::Host => self.host_config.overrides.get(lib_name), + Kind::HostSandbox => self.host_sandbox_config.overrides.get(lib_name), Kind::Target => self.target_config.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 b5b74fd9024..9daea43a4a0 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -110,7 +110,7 @@ impl TargetInfo { let mut pipelining_test = process.clone(); pipelining_test.args(&["--error-format=json", "--json=artifacts"]); let supports_pipelining = match kind { - Kind::Host => Some(rustc.cached_output(&pipelining_test).is_ok()), + Kind::Host | Kind::HostSandbox => Some(rustc.cached_output(&pipelining_test).is_ok()), Kind::Target => None, }; @@ -118,8 +118,14 @@ impl TargetInfo { .as_ref() .map(|s| s.as_str()) .unwrap_or(&rustc.host); - if kind == Kind::Target { - process.arg("--target").arg(target_triple); + match kind { + Kind::Host => {} + Kind::HostSandbox => { + process.arg("--target").arg(super::HOST_SANDBOX_TARGET); + } + Kind::Target => { + process.arg("--target").arg(target_triple); + } } let crate_type_process = process.clone(); @@ -161,6 +167,13 @@ impl TargetInfo { } rustlib } + Kind::HostSandbox => { + rustlib.push("lib"); + rustlib.push("rustlib"); + rustlib.push(super::HOST_SANDBOX_TARGET); + rustlib.push("lib"); + rustlib + } Kind::Target => { rustlib.push("lib"); rustlib.push("rustlib"); diff --git a/src/cargo/core/compiler/context/compilation_files.rs b/src/cargo/core/compiler/context/compilation_files.rs index f7e0ee7cfb8..07cc0a738e2 100644 --- a/src/cargo/core/compiler/context/compilation_files.rs +++ b/src/cargo/core/compiler/context/compilation_files.rs @@ -10,7 +10,7 @@ use log::info; use super::{BuildContext, Context, FileFlavor, Kind, Layout}; use crate::core::compiler::{CompileMode, Unit}; -use crate::core::{TargetKind, Workspace}; +use crate::core::{LibKind, TargetKind, Workspace}; use crate::util::{self, CargoResult}; /// The `Metadata` is a hash used to make unique file names for each unit in a build. @@ -53,6 +53,8 @@ impl fmt::Display for Metadata { 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 host sandbox architecture + pub(super) host_sandbox: Layout, /// The target directory layout for the target (if different from then host). pub(super) target: Option, /// Additional directory to include a copy of the outputs. @@ -93,6 +95,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { pub(super) fn new( roots: &[Unit<'a>], host: Layout, + host_sandbox: Layout, target: Option, export_dir: Option, ws: &'a Workspace<'cfg>, @@ -110,6 +113,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { CompilationFiles { ws, host, + host_sandbox, target, export_dir, roots: roots.to_vec(), @@ -122,6 +126,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { pub fn layout(&self, kind: Kind) -> &Layout { match kind { Kind::Host => &self.host, + Kind::HostSandbox => &self.host_sandbox, Kind::Target => self.target.as_ref().unwrap_or(&self.host), } } @@ -345,10 +350,10 @@ 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 = match unit.kind { + Kind::Host => &bcx.host_info, + Kind::HostSandbox => &bcx.host_sandbox_info, + Kind::Target => &bcx.target_info, }; let file_stem = self.file_stem(unit); @@ -405,8 +410,15 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { } TargetKind::ExampleLib(ref kinds) | TargetKind::Lib(ref kinds) => { for kind in kinds { + let crate_type = + if kind == &LibKind::ProcMacro && unit.kind == Kind::HostSandbox { + // wasm32-unknown-unknown doesn't support proc-macro, so just use cdylib + "cdylib" + } else { + kind.crate_type() + }; add( - kind.crate_type(), + crate_type, if kind.linkable() { FileFlavor::Linkable { rmeta: false } } else { diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index f82026e5281..813f95a7428 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -298,6 +298,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { "debug" }; let host_layout = Layout::new(self.bcx.ws, None, dest)?; + let host_sandbox_layout = Layout::new(self.bcx.ws, Some(super::build_context::HOST_SANDBOX_TARGET), dest)?; let target_layout = match self.bcx.build_config.requested_target.as_ref() { Some(target) => Some(Layout::new(self.bcx.ws, Some(target), dest)?), None => None, @@ -309,6 +310,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { let files = CompilationFiles::new( units, host_layout, + host_sandbox_layout, target_layout, export_dir, self.bcx.ws, @@ -327,6 +329,10 @@ impl<'a, 'cfg> Context<'a, 'cfg> { .host .prepare() .chain_err(|| internal("couldn't prepare build directories"))?; + self.files_mut() + .host_sandbox + .prepare() + .chain_err(|| internal("couldn't prepare build directories"))?; if let Some(ref mut target) = self.files.as_mut().unwrap().target { target .prepare() diff --git a/src/cargo/core/compiler/context/unit_dependencies.rs b/src/cargo/core/compiler/context/unit_dependencies.rs index 5cb41e6385d..407f121576b 100644 --- a/src/cargo/core/compiler/context/unit_dependencies.rs +++ b/src/cargo/core/compiler/context/unit_dependencies.rs @@ -187,7 +187,7 @@ fn compute_deps<'a, 'cfg, 'tmp>( { let unit = new_unit(bcx, pkg, lib, dep_unit_for, Kind::Target, mode); ret.push((unit, dep_unit_for)); - let unit = new_unit(bcx, pkg, lib, dep_unit_for, Kind::Host, mode); + let unit = new_unit(bcx, pkg, lib, dep_unit_for, unit.kind.for_target(lib), mode); ret.push((unit, dep_unit_for)); } else { let unit = new_unit(bcx, pkg, lib, dep_unit_for, unit.kind.for_target(lib), mode); @@ -199,6 +199,7 @@ fn compute_deps<'a, 'cfg, 'tmp>( // all we need. If this isn't a build script, then it depends on the // build script if there is one. if unit.target.is_custom_build() { + assert_eq!(unit.kind, Kind::Host, "unit.target {:?}", unit.target); return Ok(ret); } ret.extend(dep_build_script(unit, bcx)); diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 321d8cdee76..d6fb43a5a75 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -163,6 +163,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes "TARGET", &match unit.kind { Kind::Host => bcx.host_triple(), + Kind::HostSandbox => bcx.host_sandbox_triple(), Kind::Target => bcx.target_triple(), }, ) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 5567537f095..04c986c7157 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -51,7 +51,11 @@ use crate::util::{internal, join_paths, profile}; /// These will be the same unless cross-compiling. #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] pub enum Kind { + /// Actual native host architecture Host, + /// For host, but in a wasm sandbox + HostSandbox, + /// Target architecture Target, } @@ -947,16 +951,27 @@ 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()), - ); + match unit.kind { + Kind::Host => {} + Kind::HostSandbox => { + opt( + cmd, + "--target", + "", + Some(cx.bcx.host_sandbox_triple().as_ref()), + ); + } + Kind::Target => { + opt( + cmd, + "--target", + "", + bcx.build_config + .requested_target + .as_ref() + .map(|s| s.as_ref()), + ); + } } opt(cmd, "-C", "ar=", bcx.ar(unit.kind).map(|s| s.as_ref())); @@ -1109,7 +1124,16 @@ 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::HostSandbox if target.is_custom_build() => Kind::Host, + Kind::HostSandbox => Kind::HostSandbox, + Kind::Target if target.for_host() => { + if target.wasm_sandbox() { + assert!(!target.is_custom_build(), "target {:?}", target); + Kind::HostSandbox + } else { + Kind::Host + } + } Kind::Target => Kind::Target, } } diff --git a/src/cargo/core/compiler/unit.rs b/src/cargo/core/compiler/unit.rs index 00c9841cc14..e9efad967f9 100644 --- a/src/cargo/core/compiler/unit.rs +++ b/src/cargo/core/compiler/unit.rs @@ -140,6 +140,9 @@ impl<'a> UnitInterner<'a> { kind: Kind, mode: CompileMode, ) -> Unit<'a> { + // building custom_build implies Host + assert!(!(target.is_custom_build() && mode == CompileMode::Build) || kind == Kind::Host, + "target {:?} kind {:?} mode {:?}", target, kind, mode); let inner = self.intern_inner(&UnitInner { pkg, target, diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index acda0e5700b..1e047a56ef0 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -241,6 +241,7 @@ pub struct Target { harness: bool, // whether to use the test harness (--test) for_host: bool, proc_macro: bool, + wasm_sandbox: bool, edition: Edition, } @@ -296,6 +297,7 @@ struct SerializedTarget<'a> { /// Corresponds to `--crate-type` compiler attribute. /// See https://doc.rust-lang.org/reference/linkage.html crate_types: Vec<&'a str>, + wasm_sandbox: bool, name: &'a str, src_path: Option<&'a PathBuf>, edition: &'a str, @@ -315,6 +317,7 @@ impl ser::Serialize for Target { SerializedTarget { kind: &self.kind, crate_types: self.rustc_crate_types(), + wasm_sandbox: self.wasm_sandbox, name: &self.name, src_path, edition: &self.edition.to_string(), @@ -384,6 +387,7 @@ compact_debug! { harness for_host proc_macro + wasm_sandbox edition )] } @@ -614,6 +618,7 @@ impl Target { harness: true, for_host: false, proc_macro: false, + wasm_sandbox: false, edition, tested: true, benched: true, @@ -768,6 +773,9 @@ impl Target { pub fn proc_macro(&self) -> bool { self.proc_macro } + pub fn wasm_sandbox(&self) -> bool { + self.wasm_sandbox + } pub fn edition(&self) -> Edition { self.edition } @@ -867,7 +875,17 @@ impl Target { pub fn rustc_crate_types(&self) -> Vec<&str> { match self.kind { TargetKind::Lib(ref kinds) | TargetKind::ExampleLib(ref kinds) => { - kinds.iter().map(LibKind::crate_type).collect() + kinds + .iter() + .map(|kind| { + // wasm32-unknown-unknown doesn't support proc-macro, so just use cdylib + if self.wasm_sandbox() && kind == &LibKind::ProcMacro { + "cdylib" + } else { + kind.crate_type() + } + }) + .collect() } TargetKind::CustomBuild | TargetKind::Bench @@ -908,6 +926,10 @@ impl Target { self.proc_macro = proc_macro; self } + pub fn set_wasm_sandbox(&mut self, wasm_sandbox: bool) -> &mut Target { + self.wasm_sandbox = wasm_sandbox; + self + } pub fn set_edition(&mut self, edition: Edition) -> &mut Target { self.edition = edition; self diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index dde087e0406..07e63064087 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -640,10 +640,10 @@ fn generate_targets<'a>( _ => 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 = match (target.for_host(), target.wasm_sandbox()) { + (true, false) => Kind::Host, + (true, true) => Kind::HostSandbox, + (false, _) => default_arch_kind, }; let profile = profiles.get_profile( pkg.package_id(), diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 5d9e000b807..0de14eb15d4 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1517,6 +1517,8 @@ struct TomlTarget { proc_macro: Option, #[serde(rename = "proc_macro")] proc_macro2: Option, + #[serde(rename = "wasm-sandbox")] + wasm_sandbox: Option, harness: Option, #[serde(rename = "required-features")] required_features: Option>, diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index a834fad5e1f..6241eff739b 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -769,7 +769,8 @@ fn configure(features: &Features, toml: &TomlTarget, target: &mut Target) -> Car (None, None) => t2.for_host(), (Some(true), _) | (_, Some(true)) => true, (Some(false), _) | (_, Some(false)) => false, - }); + }) + .set_wasm_sandbox(toml.wasm_sandbox.unwrap_or_else(|| t2.wasm_sandbox())); if let Some(edition) = toml.edition.clone() { features .require(Feature::edition())