Skip to content

Commit d8e62ee

Browse files
committed
Auto merge of #7425 - alexcrichton:kind-string, r=ehuss
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.
2 parents d2db2bd + f745ca7 commit d8e62ee

26 files changed

+434
-386
lines changed

crates/cargo-test-support/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1678,7 +1678,7 @@ pub static RUSTC: Rustc = Rustc::new(
16781678

16791679
/// The rustc host such as `x86_64-unknown-linux-gnu`.
16801680
pub fn rustc_host() -> String {
1681-
RUSTC.with(|r| r.host.clone())
1681+
RUSTC.with(|r| r.host.to_string())
16821682
}
16831683

16841684
pub fn is_nightly() -> bool {

src/cargo/core/compiler/build_config.rs

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
use std::cell::RefCell;
2-
use std::path::Path;
32

43
use serde::ser;
54

5+
use crate::core::compiler::{CompileKind, CompileTarget};
66
use crate::util::ProcessBuilder;
7-
use crate::util::{CargoResult, CargoResultExt, Config, RustfixDiagnosticServer};
7+
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
88

99
/// Configuration information for a rustc build.
1010
#[derive(Debug)]
1111
pub struct BuildConfig {
12-
/// The target arch triple.
13-
/// Default: host arch.
14-
pub requested_target: Option<String>,
12+
/// The requested kind of compilation for this session
13+
pub requested_kind: CompileKind,
1514
/// Number of rustc jobs to run in parallel.
1615
pub jobs: u32,
1716
/// `true` if we are building for release.
@@ -46,36 +45,21 @@ impl BuildConfig {
4645
requested_target: &Option<String>,
4746
mode: CompileMode,
4847
) -> CargoResult<BuildConfig> {
49-
let requested_target = match requested_target {
50-
&Some(ref target) if target.ends_with(".json") => {
51-
let path = Path::new(target).canonicalize().chain_err(|| {
52-
failure::format_err!("Target path {:?} is not a valid file", target)
53-
})?;
54-
Some(
55-
path.into_os_string()
56-
.into_string()
57-
.map_err(|_| failure::format_err!("Target path is not valid unicode"))?,
58-
)
59-
}
60-
other => other.clone(),
48+
let requested_kind = match requested_target {
49+
Some(s) => CompileKind::Target(CompileTarget::new(s)?),
50+
None => match config.get_string("build.target")? {
51+
Some(cfg) => {
52+
let value = if cfg.val.ends_with(".json") {
53+
let path = cfg.definition.root(config).join(&cfg.val);
54+
path.to_str().expect("must be utf-8 in toml").to_string()
55+
} else {
56+
cfg.val
57+
};
58+
CompileKind::Target(CompileTarget::new(&value)?)
59+
}
60+
None => CompileKind::Host,
61+
},
6162
};
62-
if let Some(ref s) = requested_target {
63-
if s.trim().is_empty() {
64-
failure::bail!("target was empty")
65-
}
66-
}
67-
let cfg_target = match config.get_string("build.target")? {
68-
Some(ref target) if target.val.ends_with(".json") => {
69-
let path = target.definition.root(config).join(&target.val);
70-
let path_string = path
71-
.into_os_string()
72-
.into_string()
73-
.map_err(|_| failure::format_err!("Target path is not valid unicode"));
74-
Some(path_string?)
75-
}
76-
other => other.map(|t| t.val),
77-
};
78-
let target = requested_target.or(cfg_target);
7963

8064
if jobs == Some(0) {
8165
failure::bail!("jobs must be at least 1")
@@ -91,7 +75,7 @@ impl BuildConfig {
9175
let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32);
9276

9377
Ok(BuildConfig {
94-
requested_target: target,
78+
requested_kind,
9579
jobs,
9680
release: false,
9781
mode,

src/cargo/core/compiler/build_context/mod.rs

Lines changed: 63 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
use std::collections::HashMap;
2-
use std::path::{Path, PathBuf};
3-
use std::str;
4-
5-
use cargo_platform::Cfg;
6-
use log::debug;
7-
81
use crate::core::compiler::unit::UnitInterner;
9-
use crate::core::compiler::{BuildConfig, BuildOutput, Kind, Unit};
2+
use crate::core::compiler::CompileTarget;
3+
use crate::core::compiler::{BuildConfig, BuildOutput, CompileKind, Unit};
104
use crate::core::profiles::Profiles;
11-
use crate::core::{Dependency, Workspace};
5+
use crate::core::{Dependency, InternedString, Workspace};
126
use crate::core::{PackageId, PackageSet};
137
use crate::util::errors::CargoResult;
14-
use crate::util::{profile, Config, Rustc};
8+
use crate::util::{Config, Rustc};
9+
use cargo_platform::Cfg;
10+
use std::collections::HashMap;
11+
use std::path::{Path, PathBuf};
12+
use std::str;
1513

1614
mod target_info;
1715
pub use self::target_info::{FileFlavor, TargetInfo};
@@ -33,15 +31,24 @@ pub struct BuildContext<'a, 'cfg> {
3331
pub extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
3432
pub packages: &'a PackageSet<'cfg>,
3533

36-
/// Information about the compiler.
37-
pub rustc: Rustc,
38-
/// Build information for the host arch.
39-
pub host_config: TargetConfig,
40-
/// Build information for the target.
41-
pub target_config: TargetConfig,
42-
pub target_info: TargetInfo,
43-
pub host_info: TargetInfo,
34+
/// Source of interning new units as they're created.
4435
pub units: &'a UnitInterner<'a>,
36+
37+
/// Information about the compiler that we've detected on the local system.
38+
pub rustc: Rustc,
39+
40+
/// Build information for the "host", which is information about when
41+
/// `rustc` is invoked without a `--target` flag. This is used for
42+
/// procedural macros, build scripts, etc.
43+
host_config: TargetConfig,
44+
host_info: TargetInfo,
45+
46+
/// Build information for targets that we're building for. This will be
47+
/// empty if the `--target` flag is not passed, and currently also only ever
48+
/// has at most one entry, but eventually we'd like to support multi-target
49+
/// builds with Cargo.
50+
target_config: HashMap<CompileTarget, TargetConfig>,
51+
target_info: HashMap<CompileTarget, TargetInfo>,
4552
}
4653

4754
impl<'a, 'cfg> BuildContext<'a, 'cfg> {
@@ -57,19 +64,26 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
5764
let rustc = config.load_global_rustc(Some(ws))?;
5865

5966
let host_config = TargetConfig::new(config, &rustc.host)?;
60-
let target_config = match build_config.requested_target.as_ref() {
61-
Some(triple) => TargetConfig::new(config, triple)?,
62-
None => host_config.clone(),
63-
};
64-
let (host_info, target_info) = {
65-
let _p = profile::start("BuildContext::probe_target_info");
66-
debug!("probe_target_info");
67-
let host_info =
68-
TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::Host)?;
69-
let target_info =
70-
TargetInfo::new(config, &build_config.requested_target, &rustc, Kind::Target)?;
71-
(host_info, target_info)
72-
};
67+
let host_info = TargetInfo::new(
68+
config,
69+
build_config.requested_kind,
70+
&rustc,
71+
CompileKind::Host,
72+
)?;
73+
let mut target_config = HashMap::new();
74+
let mut target_info = HashMap::new();
75+
if let CompileKind::Target(target) = build_config.requested_kind {
76+
target_config.insert(target, TargetConfig::new(config, target.short_name())?);
77+
target_info.insert(
78+
target,
79+
TargetInfo::new(
80+
config,
81+
build_config.requested_kind,
82+
&rustc,
83+
CompileKind::Target(target),
84+
)?,
85+
);
86+
}
7387

7488
Ok(BuildContext {
7589
ws,
@@ -88,38 +102,31 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
88102
}
89103

90104
/// Whether a dependency should be compiled for the host or target platform,
91-
/// specified by `Kind`.
92-
pub fn dep_platform_activated(&self, dep: &Dependency, kind: Kind) -> bool {
105+
/// specified by `CompileKind`.
106+
pub fn dep_platform_activated(&self, dep: &Dependency, kind: CompileKind) -> bool {
93107
// If this dependency is only available for certain platforms,
94108
// make sure we're only enabling it for that platform.
95109
let platform = match dep.platform() {
96110
Some(p) => p,
97111
None => return true,
98112
};
99-
let (name, info) = match kind {
100-
Kind::Host => (self.host_triple(), &self.host_info),
101-
Kind::Target => (self.target_triple(), &self.target_info),
102-
};
103-
platform.matches(name, info.cfg())
113+
let name = kind.short_name(self);
114+
platform.matches(&name, self.cfg(kind))
104115
}
105116

106117
/// Gets the user-specified linker for a particular host or target.
107-
pub fn linker(&self, kind: Kind) -> Option<&Path> {
118+
pub fn linker(&self, kind: CompileKind) -> Option<&Path> {
108119
self.target_config(kind).linker.as_ref().map(|s| s.as_ref())
109120
}
110121

111122
/// Gets the user-specified `ar` program for a particular host or target.
112-
pub fn ar(&self, kind: Kind) -> Option<&Path> {
123+
pub fn ar(&self, kind: CompileKind) -> Option<&Path> {
113124
self.target_config(kind).ar.as_ref().map(|s| s.as_ref())
114125
}
115126

116127
/// Gets the list of `cfg`s printed out from the compiler for the specified kind.
117-
pub fn cfg(&self, kind: Kind) -> &[Cfg] {
118-
let info = match kind {
119-
Kind::Host => &self.host_info,
120-
Kind::Target => &self.target_info,
121-
};
122-
info.cfg()
128+
pub fn cfg(&self, kind: CompileKind) -> &[Cfg] {
129+
self.info(kind).cfg()
123130
}
124131

125132
/// Gets the host architecture triple.
@@ -128,23 +135,15 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
128135
/// - machine: x86_64,
129136
/// - hardware-platform: unknown,
130137
/// - operating system: linux-gnu.
131-
pub fn host_triple(&self) -> &str {
132-
&self.rustc.host
133-
}
134-
135-
pub fn target_triple(&self) -> &str {
136-
self.build_config
137-
.requested_target
138-
.as_ref()
139-
.map(|s| s.as_str())
140-
.unwrap_or_else(|| self.host_triple())
138+
pub fn host_triple(&self) -> InternedString {
139+
self.rustc.host
141140
}
142141

143142
/// Gets the target configuration for a particular host or target.
144-
fn target_config(&self, kind: Kind) -> &TargetConfig {
143+
pub fn target_config(&self, kind: CompileKind) -> &TargetConfig {
145144
match kind {
146-
Kind::Host => &self.host_config,
147-
Kind::Target => &self.target_config,
145+
CompileKind::Host => &self.host_config,
146+
CompileKind::Target(s) => &self.target_config[&s],
148147
}
149148
}
150149

@@ -165,10 +164,10 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
165164
pkg.source_id().is_path() || self.config.extra_verbose()
166165
}
167166

168-
fn info(&self, kind: Kind) -> &TargetInfo {
167+
pub fn info(&self, kind: CompileKind) -> &TargetInfo {
169168
match kind {
170-
Kind::Host => &self.host_info,
171-
Kind::Target => &self.target_info,
169+
CompileKind::Host => &self.host_info,
170+
CompileKind::Target(s) => &self.target_info[&s],
172171
}
173172
}
174173

@@ -180,11 +179,8 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
180179
///
181180
/// `lib_name` is the `links` library name and `kind` is whether it is for
182181
/// Host or Target.
183-
pub fn script_override(&self, lib_name: &str, kind: Kind) -> Option<&BuildOutput> {
184-
match kind {
185-
Kind::Host => self.host_config.overrides.get(lib_name),
186-
Kind::Target => self.target_config.overrides.get(lib_name),
187-
}
182+
pub fn script_override(&self, lib_name: &str, kind: CompileKind) -> Option<&BuildOutput> {
183+
self.target_config(kind).overrides.get(lib_name)
188184
}
189185
}
190186

0 commit comments

Comments
 (0)