Skip to content
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
5 changes: 4 additions & 1 deletion src/cargo/core/compiler/build_runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,10 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
unit: unit.clone(),
args,
unstable_opts,
linker: self.compilation.target_linker(unit.kind).clone(),
linker: self
.compilation
.target_linker(unit.kind)
.map(|p| p.to_path_buf()),
script_metas,
env: artifact::get_env(&self, unit, self.unit_deps(unit))?,
});
Expand Down
47 changes: 37 additions & 10 deletions src/cargo/core/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::collections::{BTreeSet, HashMap};
use std::ffi::{OsStr, OsString};
use std::path::Path;
use std::path::PathBuf;

use cargo_platform::CfgExpr;
Expand Down Expand Up @@ -131,7 +132,7 @@ pub struct Compilation<'gctx> {
/// The runner to use for each host or target process.
runners: HashMap<CompileKind, Option<(PathBuf, Vec<String>)>>,
/// The linker to use for each host or target.
target_linkers: HashMap<CompileKind, Option<PathBuf>>,
linkers: HashMap<CompileKind, Option<PathBuf>>,

/// The total number of lint warnings emitted by the compilation.
pub lint_warning_count: usize,
Expand All @@ -158,6 +159,19 @@ impl<'gctx> Compilation<'gctx> {
let kind = explicit_host_kind(&host);
runners.insert(kind, target_runner(bcx, kind)?);
}

let mut linkers = bcx
.build_config
.requested_kinds
.iter()
.chain(Some(&CompileKind::Host))
.map(|kind| Ok((*kind, target_linker(bcx, *kind)?)))
.collect::<CargoResult<HashMap<_, _>>>()?;
if !bcx.gctx.target_applies_to_host()? {
// See above reason in runner why we do this.
let kind = explicit_host_kind(&host);
linkers.insert(kind, target_linker(bcx, kind)?);
}
Ok(Compilation {
native_dirs: BTreeSet::new(),
root_output: HashMap::new(),
Expand All @@ -176,13 +190,7 @@ impl<'gctx> Compilation<'gctx> {
rustc_workspace_wrapper_process,
primary_rustc_process,
runners,
target_linkers: bcx
.build_config
.requested_kinds
.iter()
.chain(Some(&CompileKind::Host))
.map(|kind| Ok((*kind, target_linker(bcx, *kind)?)))
.collect::<CargoResult<HashMap<_, _>>>()?,
linkers,
lint_warning_count: 0,
})
}
Expand Down Expand Up @@ -277,9 +285,28 @@ impl<'gctx> Compilation<'gctx> {
self.runners.get(&kind).and_then(|x| x.as_ref())
}

/// Gets the `[host.linker]` for host build target (build scripts and proc macros).
pub fn host_linker(&self) -> Option<&Path> {
self.linkers
.get(&CompileKind::Host)
.and_then(|x| x.as_ref())
.map(|x| x.as_path())
}

/// Gets the user-specified linker for a particular host or target.
pub fn target_linker(&self, kind: CompileKind) -> Option<PathBuf> {
self.target_linkers.get(&kind).and_then(|x| x.clone())
pub fn target_linker(&self, kind: CompileKind) -> Option<&Path> {
let target_applies_to_host = self.gctx.target_applies_to_host().unwrap_or(true);
let kind = if !target_applies_to_host && kind.is_host() {
// Use explicit host target triple when `target-applies-to-host=false`
// This ensures `host.linker` won't be accidentally applied to normal builds
explicit_host_kind(&self.host)
} else {
kind
};
self.linkers
.get(&kind)
.and_then(|x| x.as_ref())
.map(|x| x.as_path())
}

/// Returns a [`ProcessBuilder`] appropriate for running a process for the
Expand Down
7 changes: 6 additions & 1 deletion src/cargo/core/compiler/fingerprint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1635,7 +1635,12 @@ fn calculate_normal(
unit.pkg.manifest().lint_rustflags(),
));
let mut config = StableHasher::new();
if let Some(linker) = build_runner.compilation.target_linker(unit.kind) {
let linker = if unit.target.for_host() && !build_runner.bcx.gctx.target_applies_to_host()? {
build_runner.compilation.host_linker()
} else {
build_runner.compilation.target_linker(unit.kind)
};
if let Some(linker) = linker {
linker.hash(&mut config);
}
if unit.mode.is_doc() && build_runner.bcx.gctx.cli_unstable().rustdoc_map {
Expand Down
61 changes: 41 additions & 20 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1404,29 +1404,12 @@ fn build_base_args(
cmd.arg("--out-dir")
.arg(&build_runner.files().output_dir(unit));

fn opt(cmd: &mut ProcessBuilder, key: &str, prefix: &str, val: Option<&OsStr>) {
if let Some(val) = val {
let mut joined = OsString::from(prefix);
joined.push(val);
cmd.arg(key).arg(joined);
}
}

unit.kind.add_target_arg(cmd);

opt(
cmd,
"-C",
"linker=",
build_runner
.compilation
.target_linker(unit.kind)
.as_ref()
.map(|s| s.as_ref()),
);
add_codegen_linker(cmd, build_runner, unit, bcx.gctx.target_applies_to_host()?);

if incremental {
let dir = build_runner.files().incremental_dir(&unit);
opt(cmd, "-C", "incremental=", Some(dir.as_os_str()));
add_codegen_incremental(cmd, build_runner, unit)
}

let pkg_hint_mostly_unused = match hints.mostly_unused {
Expand Down Expand Up @@ -1962,6 +1945,44 @@ pub fn extern_args(
Ok(result)
}

/// Adds `-C linker=<path>` if specified.
fn add_codegen_linker(
cmd: &mut ProcessBuilder,
build_runner: &BuildRunner<'_, '_>,
unit: &Unit,
target_applies_to_host: bool,
) {
let linker = if unit.target.for_host() && !target_applies_to_host {
build_runner
.compilation
.host_linker()
.map(|s| s.as_os_str())
} else {
build_runner
.compilation
.target_linker(unit.kind)
.map(|s| s.as_os_str())
};

if let Some(linker) = linker {
let mut arg = OsString::from("linker=");
arg.push(linker);
cmd.arg("-C").arg(arg);
}
}

/// Adds `-C incremental=<path>`.
fn add_codegen_incremental(
cmd: &mut ProcessBuilder,
build_runner: &BuildRunner<'_, '_>,
unit: &Unit,
) {
let dir = build_runner.files().incremental_dir(&unit);
let mut arg = OsString::from("incremental=");
arg.push(dir.as_os_str());
cmd.arg("-C").arg(arg);
}

fn envify(s: &str) -> String {
s.chars()
.flat_map(|c| c.to_uppercase())
Expand Down
53 changes: 53 additions & 0 deletions tests/testsuite/cross_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1299,3 +1299,56 @@ fn always_emit_warnings_as_warnings_when_learning_target_info() {
"#]])
.run();
}

#[cargo_test]
fn host_linker_does_not_apply_to_binary_build() {
// `host.linker` should only apply to build scripts, not to normal binary builds.
let target = rustc_host();
let p = project()
.file(
".cargo/config.toml",
&format!(
r#"
[host]
linker = "nonexistent-host-linker"
[target.{target}]
linker = "nonexistent-target-linker"
"#,
),
)
.file("src/main.rs", "fn main() {}")
.build();

p.cargo("build -Z target-applies-to-host -Z host-config --target")
.arg(&target)
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
.with_status(101)
// Need to omit some MSVC-specific diagnostics
// because rustc prints extra stuff when linker was not found.
// https://github.com/rust-lang/rust/blob/7ad4e69ad585d8ff214f7b42d01f1959eda08f40/compiler/rustc_codegen_ssa/src/back/link.rs?plain=1#L971-L975
.with_stderr_data(str![[r#"
[COMPILING] foo v0.0.1 ([ROOT]/foo)
[ERROR] linker `nonexistent-target-linker` not found
|
= [NOTE] [NOT_FOUND]
...
"#]])
.run();

// with target-applies-to-host=false,
// host.linker should not be applied but target.linker
p.cargo("build -Z target-applies-to-host -Z host-config")
.masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
.with_status(101)
// Need to omit some MSVC-specific diagnostics
// because rustc prints extra stuff when linker was not found.
// https://github.com/rust-lang/rust/blob/7ad4e69ad585d8ff214f7b42d01f1959eda08f40/compiler/rustc_codegen_ssa/src/back/link.rs?plain=1#L971-L975
.with_stderr_data(str![[r#"
[COMPILING] foo v0.0.1 ([ROOT]/foo)
[ERROR] linker `nonexistent-target-linker` not found
|
= [NOTE] [NOT_FOUND]
...
"#]])
.run();
}