Skip to content

Commit d7c3c8c

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

File tree

13 files changed

+102
-78
lines changed

13 files changed

+102
-78
lines changed

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

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use std::path::{Path, PathBuf};
2525
use std::str::{self, FromStr};
2626
use std::sync::Arc;
2727

28-
/// Information about the platform target gleaned from querying rustc.
28+
/// Information about the platform target gleaned from querying rustc and from
29+
/// collating configs.
2930
///
3031
/// [`RustcTargetData`] keeps several of these, one for the host and the others
3132
/// for other specified targets. If no target is specified, it uses a clone from
@@ -56,6 +57,8 @@ pub struct TargetInfo {
5657
pub rustflags: Arc<[String]>,
5758
/// Extra flags to pass to `rustdoc`, see [`extra_args`].
5859
pub rustdocflags: Arc<[String]>,
60+
/// Linker to use. If the value is `None` it is left up to rustc.
61+
pub linker: Option<Arc<PathBuf>>,
5962
/// Whether or not rustc (stably) supports the `--check-cfg` flag.
6063
///
6164
/// Can be removed once the minimum supported rustc version of Cargo is
@@ -159,6 +162,11 @@ impl TargetInfo {
159162
requested_kinds: &[CompileKind],
160163
rustc: &Rustc,
161164
kind: CompileKind,
165+
// This config is used for `links_overrides` and `linker`.
166+
//
167+
// In the case of target_applies_to_host=true (default) it may contain
168+
// incorrect rustflags.
169+
target_config: &TargetConfig,
162170
) -> CargoResult<TargetInfo> {
163171
let mut rustflags =
164172
extra_args(gctx, requested_kinds, &rustc.host, None, kind, Flags::Rust)?;
@@ -323,6 +331,7 @@ impl TargetInfo {
323331
Flags::Rustdoc,
324332
)?
325333
.into(),
334+
linker: target_linker(gctx, &cfg, target_config)?.map(Arc::new),
326335
cfg,
327336
support_split_debuginfo,
328337
support_check_cfg,
@@ -828,6 +837,42 @@ fn rustflags_from_target(
828837
}
829838
}
830839

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

900944
// This config is used for link overrides and choosing a linker.
901945
let host_config = if target_applies_to_host {
902946
gctx.target_cfg_triple(&rustc.host)?
903947
} else {
904948
gctx.host_cfg_triple(&rustc.host)?
905949
};
950+
let host_info = TargetInfo::new(
951+
gctx,
952+
requested_kinds,
953+
&rustc,
954+
CompileKind::Host,
955+
&host_config,
956+
)?;
906957

907958
// This is a hack. The unit_dependency graph builder "pretends" that
908959
// `CompileKind::Host` is `CompileKind::Target(host)` if the
909960
// `--target` flag is not specified. Since the unit_dependency code
910961
// needs access to the target config data, create a copy so that it
911962
// can be found. See `rebuild_unit_graph_shared` for why this is done.
912963
if requested_kinds.iter().any(CompileKind::is_host) {
913-
target_config.insert(host_target, gctx.target_cfg_triple(&rustc.host)?);
964+
let host_target_config = gctx.target_cfg_triple(&rustc.host)?;
914965

915966
// If target_applies_to_host is true, the host_info is the target info,
916967
// otherwise we need to build target info for the target.
@@ -922,9 +973,12 @@ impl<'gctx> RustcTargetData<'gctx> {
922973
requested_kinds,
923974
&rustc,
924975
CompileKind::Target(host_target),
976+
&host_target_config,
925977
)?;
926978
target_info.insert(host_target, host_target_info);
927979
}
980+
981+
target_config.insert(host_target, host_target_config);
928982
};
929983

930984
let mut res = RustcTargetData {
@@ -971,14 +1025,20 @@ impl<'gctx> RustcTargetData<'gctx> {
9711025
/// Insert `kind` into our `target_info` and `target_config` members if it isn't present yet.
9721026
pub fn merge_compile_kind(&mut self, kind: CompileKind) -> CargoResult<()> {
9731027
if let CompileKind::Target(target) = kind {
974-
if !self.target_config.contains_key(&target) {
975-
self.target_config
976-
.insert(target, self.gctx.target_cfg_triple(target.short_name())?);
977-
}
1028+
let target_config: &TargetConfig = match self.target_config.entry(target) {
1029+
Entry::Occupied(o) => o.into_mut(),
1030+
Entry::Vacant(v) => v.insert(self.gctx.target_cfg_triple(target.short_name())?),
1031+
};
9781032
if !self.target_info.contains_key(&target) {
9791033
self.target_info.insert(
9801034
target,
981-
TargetInfo::new(self.gctx, &self.requested_kinds, &self.rustc, kind)?,
1035+
TargetInfo::new(
1036+
self.gctx,
1037+
&self.requested_kinds,
1038+
&self.rustc,
1039+
kind,
1040+
target_config,
1041+
)?,
9821042
);
9831043
}
9841044
}

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

Lines changed: 0 additions & 1 deletion
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

Lines changed: 0 additions & 52 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 5 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ pub fn generate_std_roots(
219219
features.clone(),
220220
target_data.info(*kind).rustflags.clone(),
221221
target_data.info(*kind).rustdocflags.clone(),
222+
target_data.info(*kind).linker.clone(),
222223
/*is_std*/ true,
223224
/*dep_hash*/ 0,
224225
IsArtifact::No,

src/cargo/core/compiler/unit.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::collections::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

@@ -82,6 +83,8 @@ pub struct UnitInner {
8283
/// [`BuildContext::extra_args_for`]: crate::core::compiler::build_context::BuildContext::extra_args_for
8384
/// [`TargetInfo.rustdocflags`]: crate::core::compiler::build_context::TargetInfo::rustdocflags
8485
pub rustdocflags: Arc<[String]>,
86+
/// Linker (if any) to pass to `rustc`, if not specified rustc chooses a default.
87+
pub linker: Option<Arc<PathBuf>>,
8588
// if `true`, the dependency is an artifact dependency, requiring special handling when
8689
// calculating output directories, linkage and environment variables provided to builds.
8790
pub artifact: IsArtifact,
@@ -176,6 +179,7 @@ impl fmt::Debug for Unit {
176179
.field("features", &self.features)
177180
.field("rustflags", &self.rustflags)
178181
.field("rustdocflags", &self.rustdocflags)
182+
.field("linker", &self.linker)
179183
.field("artifact", &self.artifact.is_true())
180184
.field(
181185
"artifact_target_for_features",
@@ -225,6 +229,7 @@ impl UnitInterner {
225229
features: Vec<InternedString>,
226230
rustflags: Arc<[String]>,
227231
rustdocflags: Arc<[String]>,
232+
linker: Option<Arc<PathBuf>>,
228233
is_std: bool,
229234
dep_hash: u64,
230235
artifact: IsArtifact,
@@ -260,6 +265,7 @@ impl UnitInterner {
260265
features,
261266
rustflags,
262267
rustdocflags,
268+
linker,
263269
is_std,
264270
dep_hash,
265271
artifact,

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,7 @@ fn new_unit_dep_with_profile(
861861
features,
862862
state.target_data.info(kind).rustflags.clone(),
863863
state.target_data.info(kind).rustdocflags.clone(),
864+
state.target_data.info(kind).linker.clone(),
864865
state.is_std,
865866
/*dep_hash*/ 0,
866867
artifact.map_or(IsArtifact::No, |_| IsArtifact::Yes),

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 14 additions & 1 deletion
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 {
@@ -698,6 +708,7 @@ fn traverse_and_share(
698708
unit.features.clone(),
699709
unit.rustflags.clone(),
700710
unit.rustdocflags.clone(),
711+
unit.linker.clone(),
701712
unit.is_std,
702713
unit.dep_hash,
703714
unit.artifact,
@@ -725,6 +736,7 @@ fn traverse_and_share(
725736
unit.features.clone(),
726737
unit.rustflags.clone(),
727738
unit.rustdocflags.clone(),
739+
unit.linker.clone(),
728740
unit.is_std,
729741
new_dep_hash,
730742
unit.artifact,
@@ -888,6 +900,7 @@ fn override_rustc_crate_types(
888900
unit.features.clone(),
889901
unit.rustflags.clone(),
890902
unit.rustdocflags.clone(),
903+
unit.linker.clone(),
891904
unit.is_std,
892905
unit.dep_hash,
893906
unit.artifact,

src/cargo/ops/cargo_compile/unit_generator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ impl<'a> UnitGenerator<'a, '_> {
173173
features.clone(),
174174
self.target_data.info(kind).rustflags.clone(),
175175
self.target_data.info(kind).rustdocflags.clone(),
176+
self.target_data.info(kind).linker.clone(),
176177
/*is_std*/ false,
177178
/*dep_hash*/ 0,
178179
IsArtifact::No,

0 commit comments

Comments
 (0)