Skip to content

Commit 35b924d

Browse files
committed
Fix CARGO_TARGET_triple_LINKER environment variable.
1 parent 4111e1a commit 35b924d

File tree

9 files changed

+148
-132
lines changed

9 files changed

+148
-132
lines changed

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
6464
) -> CargoResult<BuildContext<'a, 'cfg>> {
6565
let rustc = config.load_global_rustc(Some(ws))?;
6666

67-
let host_config = config.get(&format!("target.{}", rustc.host))?;
67+
let host_config = config.target_cfg_triple(&rustc.host)?;
6868
let host_info = TargetInfo::new(
6969
config,
7070
build_config.requested_kind,
@@ -74,7 +74,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
7474
let mut target_config = HashMap::new();
7575
let mut target_info = HashMap::new();
7676
if let CompileKind::Target(target) = build_config.requested_kind {
77-
let tcfg = config.get(&format!("target.{}", target.short_name()))?;
77+
let tcfg = config.target_cfg_triple(target.short_name())?;
7878
target_config.insert(target, tcfg);
7979
target_info.insert(
8080
target,
@@ -124,14 +124,6 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
124124
.map(|l| l.val.clone().resolve_program(self.config))
125125
}
126126

127-
/// Gets the user-specified `ar` program for a particular host or target.
128-
pub fn ar(&self, kind: CompileKind) -> Option<PathBuf> {
129-
self.target_config(kind)
130-
.ar
131-
.as_ref()
132-
.map(|ar| ar.val.clone().resolve_program(self.config))
133-
}
134-
135127
/// Gets the list of `cfg`s printed out from the compiler for the specified kind.
136128
pub fn cfg(&self, kind: CompileKind) -> &[Cfg] {
137129
self.info(kind).cfg()

src/cargo/core/compiler/custom_build.rs

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ use crate::util::machine_message::{self, Message};
77
use crate::util::{self, internal, paths, profile};
88
use cargo_platform::Cfg;
99
use std::collections::hash_map::{Entry, HashMap};
10-
use std::collections::{BTreeMap, BTreeSet, HashSet};
10+
use std::collections::{BTreeSet, HashSet};
1111
use std::path::{Path, PathBuf};
1212
use std::str;
1313
use std::sync::Arc;
1414

1515
/// Contains the parsed output of a custom build script.
16-
#[derive(Clone, Debug, Hash)]
16+
#[derive(Clone, Debug, Hash, Default)]
1717
pub struct BuildOutput {
1818
/// Paths to pass to rustc with the `-L` flag.
1919
pub library_paths: Vec<PathBuf>,
@@ -741,82 +741,3 @@ fn prev_build_output<'a, 'cfg>(
741741
prev_script_out_dir,
742742
)
743743
}
744-
745-
impl<'de> serde::Deserialize<'de> for BuildOutput {
746-
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
747-
where
748-
D: serde::Deserializer<'de>,
749-
{
750-
use serde::de::Error;
751-
/// Helper to deserialize `BuildOutput`.
752-
#[derive(Debug, Default, serde::Deserialize)]
753-
#[serde(rename_all = "kebab-case")]
754-
#[serde(default)]
755-
struct LinksOverride {
756-
rustc_flags: Option<String>,
757-
rustc_link_lib: Vec<String>,
758-
rustc_link_search: Vec<PathBuf>,
759-
rustc_cdylib_link_arg: Vec<String>,
760-
rustc_cfg: Vec<String>,
761-
rustc_env: Option<HashMap<String, String>>,
762-
warning: Option<String>,
763-
rerun_if_changed: Option<Vec<String>>,
764-
rerun_if_env_changed: Option<Vec<String>>,
765-
#[serde(flatten)]
766-
// Sort so it is consistent and deterministic (for fingerprinting and errors).
767-
metadata: BTreeMap<String, String>,
768-
}
769-
770-
// Note: Some of this could be improved, for example using StringList
771-
// and other convenience types. I also wonder if it should maybe use
772-
// ConfigRelativePath, although that is more awkward, since it would
773-
// require an intermediate step to translate LinksOverride to
774-
// BuildOutput, converting the ConfigRelativePath values to PathBuf.
775-
776-
let lo = LinksOverride::deserialize(deserializer).map_err(|e| {
777-
serde::de::Error::custom(format!(
778-
"failed to load config [target] links override table: {}",
779-
e
780-
))
781-
})?;
782-
if lo.warning.is_some() {
783-
return Err(Error::custom(
784-
"`warning` is not supported in build script overrides",
785-
));
786-
}
787-
if lo.rerun_if_changed.is_some() {
788-
return Err(Error::custom(
789-
"`rerun-if-changed` is not supported in build script overrides",
790-
));
791-
}
792-
if lo.rerun_if_env_changed.is_some() {
793-
return Err(Error::custom(
794-
"`rerun-if-env-changed` is not supported in build script overrides",
795-
));
796-
}
797-
let mut library_paths = lo.rustc_link_search;
798-
let mut library_links = lo.rustc_link_lib;
799-
if let Some(flags) = lo.rustc_flags {
800-
let (paths, links) =
801-
BuildOutput::parse_rustc_flags(&flags, "target config").map_err(Error::custom)?;
802-
library_paths.extend(paths);
803-
library_links.extend(links);
804-
}
805-
// Convert map to vec of (key, value).
806-
let env = lo
807-
.rustc_env
808-
.map_or_else(Vec::new, |map| map.into_iter().collect());
809-
let metadata: Vec<(String, String)> = lo.metadata.into_iter().collect();
810-
Ok(BuildOutput {
811-
library_paths,
812-
library_links,
813-
linker_args: lo.rustc_cdylib_link_arg,
814-
cfgs: lo.rustc_cfg,
815-
env,
816-
metadata,
817-
rerun_if_changed: Vec::new(),
818-
rerun_if_env_changed: Vec::new(),
819-
warnings: Vec::new(),
820-
})
821-
}
822-
}

src/cargo/core/compiler/mod.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -849,12 +849,6 @@ fn build_base_args<'a, 'cfg>(
849849
cmd.arg("--target").arg(n.rustc_target());
850850
}
851851

852-
opt(
853-
cmd,
854-
"-C",
855-
"ar=",
856-
bcx.ar(unit.kind).as_ref().map(|ar| ar.as_ref()),
857-
);
858852
opt(
859853
cmd,
860854
"-C",

src/cargo/util/config/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,11 @@ impl Config {
10721072
.try_borrow_with(|| target::load_target_cfgs(self))
10731073
}
10741074

1075+
/// Returns the `[target]` table definition for the given target triple.
1076+
pub fn target_cfg_triple(&self, target: &str) -> CargoResult<TargetConfig> {
1077+
target::load_target_triple(self, target)
1078+
}
1079+
10751080
pub fn crates_io_source_id<F>(&self, f: F) -> CargoResult<SourceId>
10761081
where
10771082
F: FnMut() -> CargoResult<SourceId>,

src/cargo/util/config/target.rs

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use super::{Config, ConfigRelativePath, OptValue, PathAndArgs, StringList};
1+
use super::{Config, ConfigKey, ConfigRelativePath, OptValue, PathAndArgs, StringList, CV};
22
use crate::core::compiler::BuildOutput;
33
use crate::util::CargoResult;
44
use serde::Deserialize;
5-
use std::collections::BTreeMap;
5+
use std::collections::{BTreeMap, HashMap};
6+
use std::path::PathBuf;
67

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

2122
/// Config definition of a [target] table.
22-
#[derive(Debug, Deserialize)]
23+
#[derive(Debug)]
2324
pub struct TargetConfig {
2425
/// Process to run as a wrapper for `cargo run`, `test`, and `bench` commands.
2526
pub runner: OptValue<PathAndArgs>,
2627
/// Additional rustc flags to pass.
2728
pub rustflags: OptValue<StringList>,
2829
/// The path of the linker for this target.
2930
pub linker: OptValue<ConfigRelativePath>,
30-
/// The path of archiver (lib builder) for this target. DEPRECATED/UNUSED
31-
pub ar: OptValue<ConfigRelativePath>,
3231
/// Build script override for the given library name.
3332
///
3433
/// Any package with a `links` value for the given library name will skip
3534
/// running its build script and instead use the given output from the
3635
/// config file.
37-
#[serde(flatten)]
3836
pub links_overrides: BTreeMap<String, BuildOutput>,
3937
}
4038

39+
/// Loads all of the `target.'cfg()'` tables.
4140
pub(super) fn load_target_cfgs(config: &Config) -> CargoResult<Vec<(String, TargetCfgConfig)>> {
4241
// Load all [target] tables, filter out the cfg() entries.
4342
let mut result = Vec::new();
4443
// Use a BTreeMap so the keys are sorted. This is important for
4544
// deterministic ordering of rustflags, which affects fingerprinting and
4645
// rebuilds. We may perhaps one day wish to ensure a deterministic
4746
// ordering via the order keys were defined in files perhaps.
48-
log::debug!("Loading all targets.");
4947
let target: BTreeMap<String, TargetCfgConfig> = config.get("target")?;
5048
log::debug!("Got all targets {:#?}", target);
5149
for (key, cfg) in target {
@@ -65,3 +63,96 @@ pub(super) fn load_target_cfgs(config: &Config) -> CargoResult<Vec<(String, Targ
6563
}
6664
Ok(result)
6765
}
66+
67+
/// Loads a single `[target]` table for the given triple.
68+
pub(super) fn load_target_triple(config: &Config, triple: &str) -> CargoResult<TargetConfig> {
69+
// This needs to get each field individually because it cannot fetch the
70+
// struct all at once due to `links_overrides`. Can't use `serde(flatten)`
71+
// because it causes serde to use `deserialize_map` which means the config
72+
// deserializer does not know which keys to deserialize, which means
73+
// environment variables would not work.
74+
let runner: OptValue<PathAndArgs> = config.get(&format!("target.{}.runner", triple))?;
75+
let rustflags: OptValue<StringList> = config.get(&format!("target.{}.rustflags", triple))?;
76+
let linker: OptValue<ConfigRelativePath> = config.get(&format!("target.{}.linker", triple))?;
77+
// Links do not support environment variables.
78+
let target_key = ConfigKey::from_str(&format!("target.{}", triple));
79+
let links_overrides = match config.get_table(&target_key)? {
80+
Some(links) => parse_links_overrides(&target_key, links.val)?,
81+
None => BTreeMap::new(),
82+
};
83+
Ok(TargetConfig {
84+
runner,
85+
rustflags,
86+
linker,
87+
links_overrides,
88+
})
89+
}
90+
91+
fn parse_links_overrides(
92+
target_key: &ConfigKey,
93+
links: HashMap<String, CV>,
94+
) -> CargoResult<BTreeMap<String, BuildOutput>> {
95+
let mut links_overrides = BTreeMap::new();
96+
for (lib_name, value) in links {
97+
// Skip these keys, it shares the namespace with `TargetConfig`.
98+
match lib_name.as_str() {
99+
// `ar` is a historical thing.
100+
"ar" | "linker" | "runner" | "rustflags" => continue,
101+
_ => {}
102+
}
103+
let mut output = BuildOutput::default();
104+
let table = value.table(&format!("{}.{}", target_key, lib_name))?.0;
105+
// We require deterministic order of evaluation, so we must sort the pairs by key first.
106+
let mut pairs = Vec::new();
107+
for (k, value) in table {
108+
pairs.push((k, value));
109+
}
110+
pairs.sort_by_key(|p| p.0);
111+
for (key, value) in pairs {
112+
match key.as_str() {
113+
"rustc-flags" => {
114+
let flags = value.string(key)?;
115+
let whence = format!("target config `{}.{}` (in {})", target_key, key, flags.1);
116+
let (paths, links) = BuildOutput::parse_rustc_flags(&flags.0, &whence)?;
117+
output.library_paths.extend(paths);
118+
output.library_links.extend(links);
119+
}
120+
"rustc-link-lib" => {
121+
let list = value.list(key)?;
122+
output
123+
.library_links
124+
.extend(list.iter().map(|v| v.0.clone()));
125+
}
126+
"rustc-link-search" => {
127+
let list = value.list(key)?;
128+
output
129+
.library_paths
130+
.extend(list.iter().map(|v| PathBuf::from(&v.0)));
131+
}
132+
"rustc-cdylib-link-arg" => {
133+
let args = value.list(key)?;
134+
output.linker_args.extend(args.iter().map(|v| v.0.clone()));
135+
}
136+
"rustc-cfg" => {
137+
let list = value.list(key)?;
138+
output.cfgs.extend(list.iter().map(|v| v.0.clone()));
139+
}
140+
"rustc-env" => {
141+
for (name, val) in value.table(key)?.0 {
142+
let val = val.string(name)?.0;
143+
output.env.push((name.clone(), val.to_string()));
144+
}
145+
}
146+
"warning" | "rerun-if-changed" | "rerun-if-env-changed" => {
147+
failure::bail!("`{}` is not supported in build script overrides", key);
148+
}
149+
_ => {
150+
let val = value.string(key)?.0;
151+
output.metadata.push((key.clone(), val.to_string()));
152+
}
153+
}
154+
}
155+
links_overrides.insert(lib_name, output);
156+
}
157+
Ok(links_overrides)
158+
}

tests/testsuite/bad_config.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,10 @@ fn bad_target_links_overrides() {
13771377

13781378
p.cargo("check")
13791379
.with_status(101)
1380-
.with_stderr("[ERROR] Only `-l` and `-L` flags are allowed in target config: `foo`")
1380+
.with_stderr(
1381+
"[ERROR] Only `-l` and `-L` flags are allowed in target config \
1382+
`target.[..].rustc-flags` (in [..]foo/.cargo/config): `foo`",
1383+
)
13811384
.run();
13821385

13831386
p.change_file(

tests/testsuite/cross_compile.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ fn simple_deps() {
148148
}
149149

150150
#[cargo_test]
151-
fn linker_and_ar() {
151+
fn linker() {
152152
if cross_compile::disabled() {
153153
return;
154154
}
@@ -160,7 +160,6 @@ fn linker_and_ar() {
160160
&format!(
161161
r#"
162162
[target.{}]
163-
ar = "my-ar-tool"
164163
linker = "my-linker-tool"
165164
"#,
166165
target
@@ -192,7 +191,7 @@ fn linker_and_ar() {
192191
-C metadata=[..] \
193192
--out-dir [CWD]/target/{target}/debug/deps \
194193
--target {target} \
195-
-C ar=my-ar-tool -C linker=my-linker-tool \
194+
-C linker=my-linker-tool \
196195
-L dependency=[CWD]/target/{target}/debug/deps \
197196
-L dependency=[CWD]/target/debug/deps`
198197
",

tests/testsuite/plugins.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ fn doctest_a_plugin() {
277277

278278
// See #1515
279279
#[cargo_test]
280-
fn native_plugin_dependency_with_custom_ar_linker() {
280+
fn native_plugin_dependency_with_custom_linker() {
281281
let target = rustc_host();
282282

283283
let _foo = project()
@@ -316,7 +316,6 @@ fn native_plugin_dependency_with_custom_ar_linker() {
316316
&format!(
317317
r#"
318318
[target.{}]
319-
ar = "nonexistent-ar"
320319
linker = "nonexistent-linker"
321320
"#,
322321
target
@@ -329,7 +328,7 @@ fn native_plugin_dependency_with_custom_ar_linker() {
329328
.with_stderr_contains(
330329
"\
331330
[COMPILING] foo v0.0.1 ([..])
332-
[RUNNING] `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
331+
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
333332
[ERROR] [..]linker[..]
334333
",
335334
)

0 commit comments

Comments
 (0)