Skip to content

Commit 4e6a8d2

Browse files
committed
Fix linker value with target-applies-to-host and implicit target by storing it in Unit
1 parent a1a163f commit 4e6a8d2

File tree

14 files changed

+105
-79
lines changed

14 files changed

+105
-79
lines changed

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

+69-8
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ use serde::{Deserialize, Serialize};
2020
use std::cell::RefCell;
2121
use std::collections::hash_map::{Entry, HashMap};
2222
use std::path::{Path, PathBuf};
23+
use std::rc::Rc;
2324
use std::str::{self, FromStr};
2425
use std::sync::Arc;
2526

26-
/// Information about the platform target gleaned from querying rustc.
27+
/// Information about the platform target gleaned from querying rustc and from
28+
/// merging configs.
2729
///
2830
/// [`RustcTargetData`] keeps several of these, one for the host and the others
2931
/// for other specified targets. If no target is specified, it uses a clone from
@@ -54,6 +56,8 @@ pub struct TargetInfo {
5456
pub rustflags: Arc<[String]>,
5557
/// Extra flags to pass to `rustdoc`, see [`extra_args`].
5658
pub rustdocflags: Arc<[String]>,
59+
/// Linker to use. If the value is `None` it is left up to rustc.
60+
pub linker: Option<Rc<PathBuf>>,
5761
/// Whether or not rustc (stably) supports the `--check-cfg` flag.
5862
///
5963
/// Can be removed once the minimum supported rustc version of Cargo is
@@ -157,6 +161,11 @@ impl TargetInfo {
157161
requested_kinds: &[CompileKind],
158162
rustc: &Rustc,
159163
kind: CompileKind,
164+
// This config is used for `links_overrides` and `linker`.
165+
//
166+
// In the case of target_applies_to_host=true (default) it may contain
167+
// incorrect rustflags.
168+
target_config: &TargetConfig,
160169
) -> CargoResult<TargetInfo> {
161170
let mut rustflags =
162171
extra_args(gctx, requested_kinds, &rustc.host, None, kind, Flags::Rust)?;
@@ -321,6 +330,7 @@ impl TargetInfo {
321330
Flags::Rustdoc,
322331
)?
323332
.into(),
333+
linker: target_linker(gctx, &cfg, target_config)?.map(Rc::new),
324334
cfg,
325335
support_split_debuginfo,
326336
support_check_cfg,
@@ -826,6 +836,42 @@ fn rustflags_from_target(
826836
}
827837
}
828838

839+
/// Gets the user-specified linker for a particular host or target from the configuration.
840+
fn target_linker(
841+
gctx: &GlobalContext,
842+
target_cfg: &[Cfg],
843+
target_config: &TargetConfig,
844+
) -> CargoResult<Option<PathBuf>> {
845+
// Try host.linker and target.{}.linker.
846+
if let Some(path) = target_config
847+
.linker
848+
.as_ref()
849+
.map(|l| l.val.clone().resolve_program(gctx))
850+
{
851+
return Ok(Some(path));
852+
}
853+
854+
// Try target.'cfg(...)'.linker.
855+
let mut cfgs = gctx
856+
.target_cfgs()?
857+
.iter()
858+
.filter_map(|(key, cfg)| cfg.linker.as_ref().map(|linker| (key, linker)))
859+
.filter(|(key, _linker)| CfgExpr::matches_key(key, target_cfg));
860+
let matching_linker = cfgs.next();
861+
if let Some((key, linker)) = cfgs.next() {
862+
anyhow::bail!(
863+
"several matching instances of `target.'cfg(..)'.linker` in configurations\n\
864+
first match `{}` located in {}\n\
865+
second match `{}` located in {}",
866+
matching_linker.unwrap().0,
867+
matching_linker.unwrap().1.definition,
868+
key,
869+
linker.definition
870+
);
871+
}
872+
Ok(matching_linker.map(|(_k, linker)| linker.val.clone().resolve_program(gctx)))
873+
}
874+
829875
/// Gets compiler flags from `[host]` section in the config.
830876
/// See [`extra_args`] for more.
831877
fn rustflags_from_host(
@@ -893,22 +939,28 @@ impl<'gctx> RustcTargetData<'gctx> {
893939
let mut target_info = HashMap::new();
894940
let target_applies_to_host = gctx.target_applies_to_host()?;
895941
let host_target = CompileTarget::new(&rustc.host)?;
896-
let host_info = TargetInfo::new(gctx, requested_kinds, &rustc, CompileKind::Host)?;
897942

898943
// This config is used for link overrides and choosing a linker.
899944
let host_config = if target_applies_to_host {
900945
gctx.target_cfg_triple(&rustc.host)?
901946
} else {
902947
gctx.host_cfg_triple(&rustc.host)?
903948
};
949+
let host_info = TargetInfo::new(
950+
gctx,
951+
requested_kinds,
952+
&rustc,
953+
CompileKind::Host,
954+
&host_config,
955+
)?;
904956

905957
// This is a hack. The unit_dependency graph builder "pretends" that
906958
// `CompileKind::Host` is `CompileKind::Target(host)` if the
907959
// `--target` flag is not specified. Since the unit_dependency code
908960
// needs access to the target config data, create a copy so that it
909961
// can be found. See `rebuild_unit_graph_shared` for why this is done.
910962
if requested_kinds.iter().any(CompileKind::is_host) {
911-
target_config.insert(host_target, gctx.target_cfg_triple(&rustc.host)?);
963+
let host_target_config = gctx.target_cfg_triple(&rustc.host)?;
912964

913965
// If target_applies_to_host is true, the host_info is the target info,
914966
// otherwise we need to build target info for the target.
@@ -920,9 +972,12 @@ impl<'gctx> RustcTargetData<'gctx> {
920972
requested_kinds,
921973
&rustc,
922974
CompileKind::Target(host_target),
975+
&host_target_config,
923976
)?;
924977
target_info.insert(host_target, host_target_info);
925978
}
979+
980+
target_config.insert(host_target, host_target_config);
926981
};
927982

928983
let mut res = RustcTargetData {
@@ -969,14 +1024,20 @@ impl<'gctx> RustcTargetData<'gctx> {
9691024
/// Insert `kind` into our `target_info` and `target_config` members if it isn't present yet.
9701025
pub fn merge_compile_kind(&mut self, kind: CompileKind) -> CargoResult<()> {
9711026
if let CompileKind::Target(target) = kind {
972-
if !self.target_config.contains_key(&target) {
973-
self.target_config
974-
.insert(target, self.gctx.target_cfg_triple(target.short_name())?);
975-
}
1027+
let target_config: &TargetConfig = match self.target_config.entry(target) {
1028+
Entry::Occupied(o) => o.into_mut(),
1029+
Entry::Vacant(v) => v.insert(self.gctx.target_cfg_triple(target.short_name())?),
1030+
};
9761031
if !self.target_info.contains_key(&target) {
9771032
self.target_info.insert(
9781033
target,
979-
TargetInfo::new(self.gctx, &self.requested_kinds, &self.rustc, kind)?,
1034+
TargetInfo::new(
1035+
self.gctx,
1036+
&self.requested_kinds,
1037+
&self.rustc,
1038+
kind,
1039+
target_config,
1040+
)?,
9801041
);
9811042
}
9821043
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
284284
unit: unit.clone(),
285285
args,
286286
unstable_opts,
287-
linker: self.compilation.target_linker(unit.kind).clone(),
288287
script_meta,
289288
env: artifact::get_env(&self, self.unit_deps(unit))?,
290289
});

src/cargo/core/compiler/compilation.rs

-52
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ pub struct Doctest {
4040
pub args: Vec<OsString>,
4141
/// Whether or not -Zunstable-options is needed.
4242
pub unstable_opts: bool,
43-
/// The -Clinker value to use.
44-
pub linker: Option<PathBuf>,
4543
/// The script metadata, if this unit's package has a build script.
4644
///
4745
/// This is used for indexing [`Compilation::extra_env`].
@@ -120,8 +118,6 @@ pub struct Compilation<'gctx> {
120118
primary_rustc_process: Option<ProcessBuilder>,
121119

122120
target_runners: HashMap<CompileKind, Option<(PathBuf, Vec<String>)>>,
123-
/// The linker to use for each host or target.
124-
target_linkers: HashMap<CompileKind, Option<PathBuf>>,
125121
}
126122

127123
impl<'gctx> Compilation<'gctx> {
@@ -162,13 +158,6 @@ impl<'gctx> Compilation<'gctx> {
162158
.chain(Some(&CompileKind::Host))
163159
.map(|kind| Ok((*kind, target_runner(bcx, *kind)?)))
164160
.collect::<CargoResult<HashMap<_, _>>>()?,
165-
target_linkers: bcx
166-
.build_config
167-
.requested_kinds
168-
.iter()
169-
.chain(Some(&CompileKind::Host))
170-
.map(|kind| Ok((*kind, target_linker(bcx, *kind)?)))
171-
.collect::<CargoResult<HashMap<_, _>>>()?,
172161
})
173162
}
174163

@@ -240,11 +229,6 @@ impl<'gctx> Compilation<'gctx> {
240229
self.target_runners.get(&kind).and_then(|x| x.as_ref())
241230
}
242231

243-
/// Gets the user-specified linker for a particular host or target.
244-
pub fn target_linker(&self, kind: CompileKind) -> Option<PathBuf> {
245-
self.target_linkers.get(&kind).and_then(|x| x.clone())
246-
}
247-
248232
/// Returns a [`ProcessBuilder`] appropriate for running a process for the
249233
/// target platform. This is typically used for `cargo run` and `cargo
250234
/// test`.
@@ -484,39 +468,3 @@ fn target_runner(
484468
)
485469
}))
486470
}
487-
488-
/// Gets the user-specified linker for a particular host or target from the configuration.
489-
fn target_linker(bcx: &BuildContext<'_, '_>, kind: CompileKind) -> CargoResult<Option<PathBuf>> {
490-
// Try host.linker and target.{}.linker.
491-
if let Some(path) = bcx
492-
.target_data
493-
.target_config(kind)
494-
.linker
495-
.as_ref()
496-
.map(|l| l.val.clone().resolve_program(bcx.gctx))
497-
{
498-
return Ok(Some(path));
499-
}
500-
501-
// Try target.'cfg(...)'.linker.
502-
let target_cfg = bcx.target_data.info(kind).cfg();
503-
let mut cfgs = bcx
504-
.gctx
505-
.target_cfgs()?
506-
.iter()
507-
.filter_map(|(key, cfg)| cfg.linker.as_ref().map(|linker| (key, linker)))
508-
.filter(|(key, _linker)| CfgExpr::matches_key(key, target_cfg));
509-
let matching_linker = cfgs.next();
510-
if let Some((key, linker)) = cfgs.next() {
511-
anyhow::bail!(
512-
"several matching instances of `target.'cfg(..)'.linker` in configurations\n\
513-
first match `{}` located in {}\n\
514-
second match `{}` located in {}",
515-
matching_linker.unwrap().0,
516-
matching_linker.unwrap().1.definition,
517-
key,
518-
linker.definition
519-
);
520-
}
521-
Ok(matching_linker.map(|(_k, linker)| linker.val.clone().resolve_program(bcx.gctx)))
522-
}

src/cargo/core/compiler/custom_build.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResul
300300
cmd.env(&var, value);
301301
}
302302

303-
if let Some(linker) = &build_runner.compilation.target_linker(unit.kind) {
304-
cmd.env("RUSTC_LINKER", linker);
303+
if let Some(linker) = &unit.linker {
304+
cmd.env("RUSTC_LINKER", linker.as_ref());
305305
}
306306

307307
if let Some(links) = unit.pkg.manifest().links() {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1454,8 +1454,8 @@ fn calculate_normal(
14541454
let m = unit.pkg.manifest().metadata();
14551455
let metadata = util::hash_u64((&m.authors, &m.description, &m.homepage, &m.repository));
14561456
let mut config = StableHasher::new();
1457-
if let Some(linker) = build_runner.compilation.target_linker(unit.kind) {
1458-
linker.hash(&mut config);
1457+
if let Some(linker) = &unit.linker {
1458+
linker.as_ref().hash(&mut config);
14591459
}
14601460
if unit.mode.is_doc() && build_runner.bcx.gctx.cli_unstable().rustdoc_map {
14611461
if let Ok(map) = build_runner.bcx.gctx.doc_extern_map() {

src/cargo/core/compiler/mod.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1156,11 +1156,7 @@ fn build_base_args(
11561156
cmd,
11571157
"-C",
11581158
"linker=",
1159-
build_runner
1160-
.compilation
1161-
.target_linker(unit.kind)
1162-
.as_ref()
1163-
.map(|s| s.as_ref()),
1159+
unit.linker.as_ref().map(|s| s.as_ref().as_ref()),
11641160
);
11651161
if incremental {
11661162
let dir = build_runner

src/cargo/core/compiler/standard_lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ pub fn generate_std_roots(
220220
target_data.info(*kind).rustflags.clone(),
221221
target_data.info(*kind).rustdocflags.clone(),
222222
target_data.target_config(*kind).links_overrides.clone(),
223+
target_data.info(*kind).linker.clone(),
223224
/*is_std*/ true,
224225
/*dep_hash*/ 0,
225226
IsArtifact::No,

src/cargo/core/compiler/unit.rs

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::collections::{BTreeMap, HashSet};
1313
use std::fmt;
1414
use std::hash::{Hash, Hasher};
1515
use std::ops::Deref;
16+
use std::path::PathBuf;
1617
use std::rc::Rc;
1718
use std::sync::Arc;
1819

@@ -90,6 +91,8 @@ pub struct UnitInner {
9091
/// running its build script and instead use the given output from the
9192
/// config file.
9293
pub links_overrides: Rc<BTreeMap<String, BuildOutput>>,
94+
/// Linker (if any) to pass to `rustc`, if not specified rustc chooses a default.
95+
pub linker: Option<Rc<PathBuf>>,
9396
// if `true`, the dependency is an artifact dependency, requiring special handling when
9497
// calculating output directories, linkage and environment variables provided to builds.
9598
pub artifact: IsArtifact,
@@ -185,6 +188,7 @@ impl fmt::Debug for Unit {
185188
.field("rustflags", &self.rustflags)
186189
.field("rustdocflags", &self.rustdocflags)
187190
.field("links_overrides", &self.links_overrides)
191+
.field("linker", &self.linker)
188192
.field("artifact", &self.artifact.is_true())
189193
.field(
190194
"artifact_target_for_features",
@@ -235,6 +239,7 @@ impl UnitInterner {
235239
rustflags: Arc<[String]>,
236240
rustdocflags: Arc<[String]>,
237241
links_overrides: Rc<BTreeMap<String, BuildOutput>>,
242+
linker: Option<Rc<PathBuf>>,
238243
is_std: bool,
239244
dep_hash: u64,
240245
artifact: IsArtifact,
@@ -271,6 +276,7 @@ impl UnitInterner {
271276
rustflags,
272277
rustdocflags,
273278
links_overrides,
279+
linker,
274280
is_std,
275281
dep_hash,
276282
artifact,

src/cargo/core/compiler/unit_dependencies.rs

+1
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ fn new_unit_dep_with_profile(
862862
.target_config(kind)
863863
.links_overrides
864864
.clone(),
865+
state.target_data.info(kind).linker.clone(),
865866
state.is_std,
866867
/*dep_hash*/ 0,
867868
artifact.map_or(IsArtifact::No, |_| IsArtifact::Yes),

src/cargo/ops/cargo_compile/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,17 @@ pub fn print<'a>(
178178
if index != 0 {
179179
drop_println!(gctx);
180180
}
181-
let target_info = TargetInfo::new(gctx, &build_config.requested_kinds, &rustc, *kind)?;
181+
let target_config = match kind {
182+
CompileKind::Host => gctx.target_cfg_triple(&rustc.host),
183+
CompileKind::Target(target) => gctx.target_cfg_triple(target.short_name()),
184+
}?;
185+
let target_info = TargetInfo::new(
186+
gctx,
187+
&build_config.requested_kinds,
188+
&rustc,
189+
*kind,
190+
&target_config,
191+
)?;
182192
let mut process = rustc.process();
183193
process.args(&target_info.rustflags);
184194
if let Some(args) = target_rustc_args {
@@ -699,6 +709,7 @@ fn traverse_and_share(
699709
unit.rustflags.clone(),
700710
unit.rustdocflags.clone(),
701711
unit.links_overrides.clone(),
712+
unit.linker.clone(),
702713
unit.is_std,
703714
unit.dep_hash,
704715
unit.artifact,
@@ -727,6 +738,7 @@ fn traverse_and_share(
727738
unit.rustflags.clone(),
728739
unit.rustdocflags.clone(),
729740
unit.links_overrides.clone(),
741+
unit.linker.clone(),
730742
unit.is_std,
731743
new_dep_hash,
732744
unit.artifact,
@@ -891,6 +903,7 @@ fn override_rustc_crate_types(
891903
unit.rustflags.clone(),
892904
unit.rustdocflags.clone(),
893905
unit.links_overrides.clone(),
906+
unit.linker.clone(),
894907
unit.is_std,
895908
unit.dep_hash,
896909
unit.artifact,

src/cargo/ops/cargo_compile/unit_generator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ impl<'a> UnitGenerator<'a, '_> {
174174
self.target_data.info(kind).rustflags.clone(),
175175
self.target_data.info(kind).rustdocflags.clone(),
176176
self.target_data.target_config(kind).links_overrides.clone(),
177+
self.target_data.info(kind).linker.clone(),
177178
/*is_std*/ false,
178179
/*dep_hash*/ 0,
179180
IsArtifact::No,

0 commit comments

Comments
 (0)