Skip to content

Fix CARGO_TARGET_triple_LINKER environment variable. #7763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions src/cargo/core/compiler/build_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
) -> CargoResult<BuildContext<'a, 'cfg>> {
let rustc = config.load_global_rustc(Some(ws))?;

let host_config = config.get(&format!("target.{}", rustc.host))?;
let host_config = config.target_cfg_triple(&rustc.host)?;
let host_info = TargetInfo::new(
config,
build_config.requested_kind,
Expand All @@ -74,7 +74,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
let mut target_config = HashMap::new();
let mut target_info = HashMap::new();
if let CompileKind::Target(target) = build_config.requested_kind {
let tcfg = config.get(&format!("target.{}", target.short_name()))?;
let tcfg = config.target_cfg_triple(target.short_name())?;
target_config.insert(target, tcfg);
target_info.insert(
target,
Expand Down Expand Up @@ -124,14 +124,6 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
.map(|l| l.val.clone().resolve_program(self.config))
}

/// Gets the user-specified `ar` program for a particular host or target.
pub fn ar(&self, kind: CompileKind) -> Option<PathBuf> {
self.target_config(kind)
.ar
.as_ref()
.map(|ar| ar.val.clone().resolve_program(self.config))
}

/// Gets the list of `cfg`s printed out from the compiler for the specified kind.
pub fn cfg(&self, kind: CompileKind) -> &[Cfg] {
self.info(kind).cfg()
Expand Down
83 changes: 2 additions & 81 deletions src/cargo/core/compiler/custom_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use crate::util::machine_message::{self, Message};
use crate::util::{self, internal, paths, profile};
use cargo_platform::Cfg;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::collections::{BTreeSet, HashSet};
use std::path::{Path, PathBuf};
use std::str;
use std::sync::Arc;

/// Contains the parsed output of a custom build script.
#[derive(Clone, Debug, Hash)]
#[derive(Clone, Debug, Hash, Default)]
pub struct BuildOutput {
/// Paths to pass to rustc with the `-L` flag.
pub library_paths: Vec<PathBuf>,
Expand Down Expand Up @@ -741,82 +741,3 @@ fn prev_build_output<'a, 'cfg>(
prev_script_out_dir,
)
}

impl<'de> serde::Deserialize<'de> for BuildOutput {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
/// Helper to deserialize `BuildOutput`.
#[derive(Debug, Default, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
#[serde(default)]
struct LinksOverride {
rustc_flags: Option<String>,
rustc_link_lib: Vec<String>,
rustc_link_search: Vec<PathBuf>,
rustc_cdylib_link_arg: Vec<String>,
rustc_cfg: Vec<String>,
rustc_env: Option<HashMap<String, String>>,
warning: Option<String>,
rerun_if_changed: Option<Vec<String>>,
rerun_if_env_changed: Option<Vec<String>>,
#[serde(flatten)]
// Sort so it is consistent and deterministic (for fingerprinting and errors).
metadata: BTreeMap<String, String>,
}

// Note: Some of this could be improved, for example using StringList
// and other convenience types. I also wonder if it should maybe use
// ConfigRelativePath, although that is more awkward, since it would
// require an intermediate step to translate LinksOverride to
// BuildOutput, converting the ConfigRelativePath values to PathBuf.

let lo = LinksOverride::deserialize(deserializer).map_err(|e| {
serde::de::Error::custom(format!(
"failed to load config [target] links override table: {}",
e
))
})?;
if lo.warning.is_some() {
return Err(Error::custom(
"`warning` is not supported in build script overrides",
));
}
if lo.rerun_if_changed.is_some() {
return Err(Error::custom(
"`rerun-if-changed` is not supported in build script overrides",
));
}
if lo.rerun_if_env_changed.is_some() {
return Err(Error::custom(
"`rerun-if-env-changed` is not supported in build script overrides",
));
}
let mut library_paths = lo.rustc_link_search;
let mut library_links = lo.rustc_link_lib;
if let Some(flags) = lo.rustc_flags {
let (paths, links) =
BuildOutput::parse_rustc_flags(&flags, "target config").map_err(Error::custom)?;
library_paths.extend(paths);
library_links.extend(links);
}
// Convert map to vec of (key, value).
let env = lo
.rustc_env
.map_or_else(Vec::new, |map| map.into_iter().collect());
let metadata: Vec<(String, String)> = lo.metadata.into_iter().collect();
Ok(BuildOutput {
library_paths,
library_links,
linker_args: lo.rustc_cdylib_link_arg,
cfgs: lo.rustc_cfg,
env,
metadata,
rerun_if_changed: Vec::new(),
rerun_if_env_changed: Vec::new(),
warnings: Vec::new(),
})
}
}
6 changes: 0 additions & 6 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,12 +849,6 @@ fn build_base_args<'a, 'cfg>(
cmd.arg("--target").arg(n.rustc_target());
}

opt(
cmd,
"-C",
"ar=",
bcx.ar(unit.kind).as_ref().map(|ar| ar.as_ref()),
);
opt(
cmd,
"-C",
Expand Down
5 changes: 5 additions & 0 deletions src/cargo/util/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,11 @@ impl Config {
.try_borrow_with(|| target::load_target_cfgs(self))
}

/// Returns the `[target]` table definition for the given target triple.
pub fn target_cfg_triple(&self, target: &str) -> CargoResult<TargetConfig> {
target::load_target_triple(self, target)
}

pub fn crates_io_source_id<F>(&self, f: F) -> CargoResult<SourceId>
where
F: FnMut() -> CargoResult<SourceId>,
Expand Down
105 changes: 98 additions & 7 deletions src/cargo/util/config/target.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use super::{Config, ConfigRelativePath, OptValue, PathAndArgs, StringList};
use super::{Config, ConfigKey, ConfigRelativePath, OptValue, PathAndArgs, StringList, CV};
use crate::core::compiler::BuildOutput;
use crate::util::CargoResult;
use serde::Deserialize;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::path::PathBuf;

/// Config definition of a [target.'cfg(…)'] table.
///
Expand All @@ -19,33 +20,30 @@ pub struct TargetCfgConfig {
}

/// Config definition of a [target] table.
#[derive(Debug, Deserialize)]
#[derive(Debug)]
pub struct TargetConfig {
/// Process to run as a wrapper for `cargo run`, `test`, and `bench` commands.
pub runner: OptValue<PathAndArgs>,
/// Additional rustc flags to pass.
pub rustflags: OptValue<StringList>,
/// The path of the linker for this target.
pub linker: OptValue<ConfigRelativePath>,
/// The path of archiver (lib builder) for this target. DEPRECATED/UNUSED
pub ar: OptValue<ConfigRelativePath>,
/// Build script override for the given library name.
///
/// Any package with a `links` value for the given library name will skip
/// running its build script and instead use the given output from the
/// config file.
#[serde(flatten)]
pub links_overrides: BTreeMap<String, BuildOutput>,
}

/// Loads all of the `target.'cfg()'` tables.
pub(super) fn load_target_cfgs(config: &Config) -> CargoResult<Vec<(String, TargetCfgConfig)>> {
// Load all [target] tables, filter out the cfg() entries.
let mut result = Vec::new();
// Use a BTreeMap so the keys are sorted. This is important for
// deterministic ordering of rustflags, which affects fingerprinting and
// rebuilds. We may perhaps one day wish to ensure a deterministic
// ordering via the order keys were defined in files perhaps.
log::debug!("Loading all targets.");
let target: BTreeMap<String, TargetCfgConfig> = config.get("target")?;
log::debug!("Got all targets {:#?}", target);
for (key, cfg) in target {
Expand All @@ -65,3 +63,96 @@ pub(super) fn load_target_cfgs(config: &Config) -> CargoResult<Vec<(String, Targ
}
Ok(result)
}

/// Loads a single `[target]` table for the given triple.
pub(super) fn load_target_triple(config: &Config, triple: &str) -> CargoResult<TargetConfig> {
// This needs to get each field individually because it cannot fetch the
// struct all at once due to `links_overrides`. Can't use `serde(flatten)`
// because it causes serde to use `deserialize_map` which means the config
// deserializer does not know which keys to deserialize, which means
// environment variables would not work.
let runner: OptValue<PathAndArgs> = config.get(&format!("target.{}.runner", triple))?;
let rustflags: OptValue<StringList> = config.get(&format!("target.{}.rustflags", triple))?;
let linker: OptValue<ConfigRelativePath> = config.get(&format!("target.{}.linker", triple))?;
// Links do not support environment variables.
let target_key = ConfigKey::from_str(&format!("target.{}", triple));
let links_overrides = match config.get_table(&target_key)? {
Some(links) => parse_links_overrides(&target_key, links.val)?,
None => BTreeMap::new(),
};
Ok(TargetConfig {
runner,
rustflags,
linker,
links_overrides,
})
}

fn parse_links_overrides(
target_key: &ConfigKey,
links: HashMap<String, CV>,
) -> CargoResult<BTreeMap<String, BuildOutput>> {
let mut links_overrides = BTreeMap::new();
for (lib_name, value) in links {
// Skip these keys, it shares the namespace with `TargetConfig`.
match lib_name.as_str() {
// `ar` is a historical thing.
"ar" | "linker" | "runner" | "rustflags" => continue,
_ => {}
}
let mut output = BuildOutput::default();
let table = value.table(&format!("{}.{}", target_key, lib_name))?.0;
// We require deterministic order of evaluation, so we must sort the pairs by key first.
let mut pairs = Vec::new();
for (k, value) in table {
pairs.push((k, value));
}
pairs.sort_by_key(|p| p.0);
for (key, value) in pairs {
match key.as_str() {
"rustc-flags" => {
let flags = value.string(key)?;
let whence = format!("target config `{}.{}` (in {})", target_key, key, flags.1);
let (paths, links) = BuildOutput::parse_rustc_flags(&flags.0, &whence)?;
output.library_paths.extend(paths);
output.library_links.extend(links);
}
"rustc-link-lib" => {
let list = value.list(key)?;
output
.library_links
.extend(list.iter().map(|v| v.0.clone()));
}
"rustc-link-search" => {
let list = value.list(key)?;
output
.library_paths
.extend(list.iter().map(|v| PathBuf::from(&v.0)));
}
"rustc-cdylib-link-arg" => {
let args = value.list(key)?;
output.linker_args.extend(args.iter().map(|v| v.0.clone()));
}
"rustc-cfg" => {
let list = value.list(key)?;
output.cfgs.extend(list.iter().map(|v| v.0.clone()));
}
"rustc-env" => {
for (name, val) in value.table(key)?.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", key);
}
_ => {
let val = value.string(key)?.0;
output.metadata.push((key.clone(), val.to_string()));
}
}
}
links_overrides.insert(lib_name, output);
}
Ok(links_overrides)
}
5 changes: 4 additions & 1 deletion tests/testsuite/bad_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1377,7 +1377,10 @@ fn bad_target_links_overrides() {

p.cargo("check")
.with_status(101)
.with_stderr("[ERROR] Only `-l` and `-L` flags are allowed in target config: `foo`")
.with_stderr(
"[ERROR] Only `-l` and `-L` flags are allowed in target config \
`target.[..].rustc-flags` (in [..]foo/.cargo/config): `foo`",
)
.run();

p.change_file(
Expand Down
5 changes: 2 additions & 3 deletions tests/testsuite/cross_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ fn simple_deps() {
}

#[cargo_test]
fn linker_and_ar() {
fn linker() {
if cross_compile::disabled() {
return;
}
Expand All @@ -160,7 +160,6 @@ fn linker_and_ar() {
&format!(
r#"
[target.{}]
ar = "my-ar-tool"
linker = "my-linker-tool"
"#,
target
Expand Down Expand Up @@ -192,7 +191,7 @@ fn linker_and_ar() {
-C metadata=[..] \
--out-dir [CWD]/target/{target}/debug/deps \
--target {target} \
-C ar=my-ar-tool -C linker=my-linker-tool \
-C linker=my-linker-tool \
-L dependency=[CWD]/target/{target}/debug/deps \
-L dependency=[CWD]/target/debug/deps`
",
Expand Down
5 changes: 2 additions & 3 deletions tests/testsuite/plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ fn doctest_a_plugin() {

// See #1515
#[cargo_test]
fn native_plugin_dependency_with_custom_ar_linker() {
fn native_plugin_dependency_with_custom_linker() {
let target = rustc_host();

let _foo = project()
Expand Down Expand Up @@ -316,7 +316,6 @@ fn native_plugin_dependency_with_custom_ar_linker() {
&format!(
r#"
[target.{}]
ar = "nonexistent-ar"
linker = "nonexistent-linker"
"#,
target
Expand All @@ -329,7 +328,7 @@ fn native_plugin_dependency_with_custom_ar_linker() {
.with_stderr_contains(
"\
[COMPILING] foo v0.0.1 ([..])
[RUNNING] `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
[ERROR] [..]linker[..]
",
)
Expand Down
Loading