use crate::core::compiler::unit::UnitInterner;
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};
use crate::util::errors::CargoResult;
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};
pub struct BuildContext<'a, 'cfg> {
pub ws: &'a Workspace<'cfg>,
pub config: &'cfg Config,
pub profiles: &'a Profiles,
pub build_config: &'a BuildConfig,
pub extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
pub packages: &'a PackageSet<'cfg>,
pub units: &'a UnitInterner<'a>,
pub rustc: Rustc,
host_config: TargetConfig,
host_info: TargetInfo,
target_config: HashMap<CompileTarget, TargetConfig>,
target_info: HashMap<CompileTarget, TargetInfo>,
}
impl<'a, 'cfg> BuildContext<'a, 'cfg> {
pub fn new(
ws: &'a Workspace<'cfg>,
packages: &'a PackageSet<'cfg>,
config: &'cfg Config,
build_config: &'a BuildConfig,
profiles: &'a Profiles,
units: &'a UnitInterner<'a>,
extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
) -> CargoResult<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_kind,
&rustc,
CompileKind::Host,
)?;
let mut target_config = HashMap::new();
let mut target_info = HashMap::new();
if let CompileKind::Target(target) = build_config.requested_kind {
target_config.insert(target, TargetConfig::new(config, target.short_name())?);
target_info.insert(
target,
TargetInfo::new(
config,
build_config.requested_kind,
&rustc,
CompileKind::Target(target),
)?,
);
}
Ok(BuildContext {
ws,
packages,
config,
rustc,
target_config,
target_info,
host_config,
host_info,
build_config,
profiles,
extra_compiler_args,
units,
})
}
pub fn dep_platform_activated(&self, dep: &Dependency, kind: CompileKind) -> bool {
let platform = match dep.platform() {
Some(p) => p,
None => return true,
};
let name = kind.short_name(self);
platform.matches(name, self.cfg(kind))
}
pub fn linker(&self, kind: CompileKind) -> Option<&Path> {
self.target_config(kind).linker.as_ref().map(|s| s.as_ref())
}
pub fn ar(&self, kind: CompileKind) -> Option<&Path> {
self.target_config(kind).ar.as_ref().map(|s| s.as_ref())
}
pub fn cfg(&self, kind: CompileKind) -> &[Cfg] {
self.info(kind).cfg()
}
pub fn host_triple(&self) -> InternedString {
self.rustc.host
}
pub fn target_config(&self, kind: CompileKind) -> &TargetConfig {
match kind {
CompileKind::Host => &self.host_config,
CompileKind::Target(s) => &self.target_config[&s],
}
}
pub fn jobs(&self) -> u32 {
self.build_config.jobs
}
pub fn rustflags_args(&self, unit: &Unit<'_>) -> &[String] {
&self.info(unit.kind).rustflags
}
pub fn rustdocflags_args(&self, unit: &Unit<'_>) -> &[String] {
&self.info(unit.kind).rustdocflags
}
pub fn show_warnings(&self, pkg: PackageId) -> bool {
pkg.source_id().is_path() || self.config.extra_verbose()
}
pub fn info(&self, kind: CompileKind) -> &TargetInfo {
match kind {
CompileKind::Host => &self.host_info,
CompileKind::Target(s) => &self.target_info[&s],
}
}
pub fn extra_args_for(&self, unit: &Unit<'a>) -> Option<&Vec<String>> {
self.extra_compiler_args.get(unit)
}
pub fn script_override(&self, lib_name: &str, kind: CompileKind) -> Option<&BuildOutput> {
self.target_config(kind).overrides.get(lib_name)
}
}
#[derive(Clone, Default)]
pub struct TargetConfig {
pub ar: Option<PathBuf>,
pub linker: Option<PathBuf>,
pub overrides: HashMap<String, BuildOutput>,
}
impl TargetConfig {
pub fn new(config: &Config, triple: &str) -> CargoResult<TargetConfig> {
let key = format!("target.{}", triple);
let mut ret = TargetConfig {
ar: config.get_path(&format!("{}.ar", key))?.map(|v| v.val),
linker: config.get_path(&format!("{}.linker", key))?.map(|v| v.val),
overrides: HashMap::new(),
};
let table = match config.get_table(&key)? {
Some(table) => table.val,
None => return Ok(ret),
};
for (lib_name, value) in table {
match lib_name.as_str() {
"ar" | "linker" | "runner" | "rustflags" => continue,
_ => {}
}
let mut output = BuildOutput {
library_paths: Vec::new(),
library_links: Vec::new(),
linker_args: Vec::new(),
cfgs: Vec::new(),
env: Vec::new(),
metadata: Vec::new(),
rerun_if_changed: Vec::new(),
rerun_if_env_changed: Vec::new(),
warnings: Vec::new(),
};
let mut pairs = Vec::new();
for (k, value) in value.table(&lib_name)?.0 {
pairs.push((k, value));
}
pairs.sort_by_key(|p| p.0);
for (k, value) in pairs {
let key = format!("{}.{}", key, k);
match &k[..] {
"rustc-flags" => {
let (flags, definition) = value.string(k)?;
let whence = format!("in `{}` (in {})", key, definition.display());
let (paths, links) = BuildOutput::parse_rustc_flags(flags, &whence)?;
output.library_paths.extend(paths);
output.library_links.extend(links);
}
"rustc-link-lib" => {
let list = value.list(k)?;
output
.library_links
.extend(list.iter().map(|v| v.0.clone()));
}
"rustc-link-search" => {
let list = value.list(k)?;
output
.library_paths
.extend(list.iter().map(|v| PathBuf::from(&v.0)));
}
"rustc-cdylib-link-arg" => {
let args = value.list(k)?;
output.linker_args.extend(args.iter().map(|v| v.0.clone()));
}
"rustc-cfg" => {
let list = value.list(k)?;
output.cfgs.extend(list.iter().map(|v| v.0.clone()));
}
"rustc-env" => {
for (name, val) in value.table(k)?.0 {
let val = val.string(name)?.0;
output.env.push((name.clone(), val.to_string()));
}
}
"warning" | "rerun-if-changed" | "rerun-if-env-changed" => {
failure::bail!("`{}` is not supported in build script overrides", k);
}
_ => {
let val = value.string(k)?.0;
output.metadata.push((k.clone(), val.to_string()));
}
}
}
ret.overrides.insert(lib_name, output);
}
Ok(ret)
}
}