Skip to content

Commit ff6d296

Browse files
committedFeb 10, 2024
refactor use of Cargo and configure_linker in bootstrap
Signed-off-by: onur-ozkan <[email protected]>
1 parent 993c72f commit ff6d296

File tree

7 files changed

+252
-187
lines changed

7 files changed

+252
-187
lines changed
 

‎src/bootstrap/src/core/build_steps/check.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use crate::core::build_steps::compile::{
44
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
55
};
66
use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType};
7-
use crate::core::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step};
7+
use crate::core::builder::{
8+
self, crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step,
9+
};
810
use crate::core::config::TargetSelection;
911
use crate::utils::cache::Interned;
1012
use crate::INTERNER;
@@ -110,14 +112,15 @@ impl Step for Std {
110112
let target = self.target;
111113
let compiler = builder.compiler(builder.top_stage, builder.config.build);
112114

113-
let mut cargo = builder.cargo(
115+
let mut cargo = builder::Cargo::new(
116+
builder,
114117
compiler,
115118
Mode::Std,
116119
SourceType::InTree,
117120
target,
118121
cargo_subcommand(builder.kind),
119-
false,
120122
);
123+
121124
std_cargo(builder, target, compiler.stage, &mut cargo);
122125
if matches!(builder.config.cmd, Subcommand::Fix { .. }) {
123126
// By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot.
@@ -163,13 +166,13 @@ impl Step for Std {
163166
// since we initialize with an empty sysroot.
164167
//
165168
// Currently only the "libtest" tree of crates does this.
166-
let mut cargo = builder.cargo(
169+
let mut cargo = builder::Cargo::new(
170+
builder,
167171
compiler,
168172
Mode::Std,
169173
SourceType::InTree,
170174
target,
171175
cargo_subcommand(builder.kind),
172-
false,
173176
);
174177

175178
// If we're not in stage 0, tests and examples will fail to compile
@@ -258,14 +261,15 @@ impl Step for Rustc {
258261
builder.ensure(Std::new(target));
259262
}
260263

261-
let mut cargo = builder.cargo(
264+
let mut cargo = builder::Cargo::new(
265+
builder,
262266
compiler,
263267
Mode::Rustc,
264268
SourceType::InTree,
265269
target,
266270
cargo_subcommand(builder.kind),
267-
false,
268271
);
272+
269273
rustc_cargo(builder, &mut cargo, target, compiler.stage);
270274

271275
// For ./x.py clippy, don't run with --all-targets because
@@ -335,14 +339,15 @@ impl Step for CodegenBackend {
335339

336340
builder.ensure(Rustc::new(target, builder));
337341

338-
let mut cargo = builder.cargo(
342+
let mut cargo = builder::Cargo::new(
343+
builder,
339344
compiler,
340345
Mode::Codegen,
341346
SourceType::InTree,
342347
target,
343348
cargo_subcommand(builder.kind),
344-
false,
345349
);
350+
346351
cargo
347352
.arg("--manifest-path")
348353
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));

‎src/bootstrap/src/core/build_steps/compile.rs

+37-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use serde_derive::Deserialize;
2222
use crate::core::build_steps::dist;
2323
use crate::core::build_steps::llvm;
2424
use crate::core::build_steps::tool::SourceType;
25+
use crate::core::builder;
2526
use crate::core::builder::crate_description;
2627
use crate::core::builder::Cargo;
2728
use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
@@ -233,25 +234,35 @@ impl Step for Std {
233234
}
234235
}
235236

236-
let mut cargo = builder.cargo(
237-
compiler,
238-
Mode::Std,
239-
SourceType::InTree,
240-
target,
241-
if self.is_for_mir_opt_tests { "check" } else { "build" },
242-
self.is_for_mir_opt_tests,
243-
);
244237
// We build a sysroot for mir-opt tests using the same trick that Miri does: A check build
245238
// with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
246239
// fact that this is a check build integrates nicely with run_cargo.
247-
if self.is_for_mir_opt_tests {
240+
let mut cargo = if self.is_for_mir_opt_tests {
241+
let mut cargo = builder::Cargo::new_for_mir_opt_tests(
242+
builder,
243+
compiler,
244+
Mode::Std,
245+
SourceType::InTree,
246+
target,
247+
"check",
248+
);
248249
cargo.rustflag("-Zalways-encode-mir");
249250
cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml"));
251+
cargo
250252
} else {
253+
let mut cargo = builder::Cargo::new(
254+
builder,
255+
compiler,
256+
Mode::Std,
257+
SourceType::InTree,
258+
target,
259+
"build",
260+
);
251261
std_cargo(builder, target, compiler.stage, &mut cargo);
252262
for krate in &*self.crates {
253263
cargo.arg("-p").arg(krate);
254264
}
265+
cargo
255266
};
256267

257268
// See src/bootstrap/synthetic_targets.rs
@@ -915,8 +926,15 @@ impl Step for Rustc {
915926
builder.config.build,
916927
));
917928

918-
let mut cargo =
919-
builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build", false);
929+
let mut cargo = builder::Cargo::new(
930+
builder,
931+
compiler,
932+
Mode::Rustc,
933+
SourceType::InTree,
934+
target,
935+
"build",
936+
);
937+
920938
rustc_cargo(builder, &mut cargo, target, compiler.stage);
921939

922940
if builder.config.rust_profile_use.is_some()
@@ -1336,8 +1354,14 @@ impl Step for CodegenBackend {
13361354

13371355
let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
13381356

1339-
let mut cargo =
1340-
builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build", false);
1357+
let mut cargo = builder::Cargo::new(
1358+
builder,
1359+
compiler,
1360+
Mode::Codegen,
1361+
SourceType::InTree,
1362+
target,
1363+
"build",
1364+
);
13411365
cargo
13421366
.arg("--manifest-path")
13431367
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));

‎src/bootstrap/src/core/build_steps/doc.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::{fs, mem};
1313

1414
use crate::core::build_steps::compile;
1515
use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool};
16-
use crate::core::builder::crate_description;
16+
use crate::core::builder::{self, crate_description};
1717
use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
1818
use crate::core::config::{Config, TargetSelection};
1919
use crate::utils::cache::{Interned, INTERNER};
@@ -684,7 +684,9 @@ fn doc_std(
684684
// as a function parameter.
685685
let out_dir = target_dir.join(target.triple).join("doc");
686686

687-
let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "doc", false);
687+
let mut cargo =
688+
builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, "doc");
689+
688690
compile::std_cargo(builder, target, compiler.stage, &mut cargo);
689691
cargo
690692
.arg("--no-deps")
@@ -786,7 +788,8 @@ impl Step for Rustc {
786788

787789
// Build cargo command.
788790
let mut cargo =
789-
builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc", false);
791+
builder::Cargo::new(builder, compiler, Mode::Rustc, SourceType::InTree, target, "doc");
792+
790793
cargo.rustdocflag("--document-private-items");
791794
// Since we always pass --document-private-items, there's no need to warn about linking to private items.
792795
cargo.rustdocflag("-Arustdoc::private-intra-doc-links");

‎src/bootstrap/src/core/build_steps/run.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl Step for Miri {
165165
SourceType::InTree,
166166
&[],
167167
);
168-
miri.add_rustc_lib_path(builder, compiler);
168+
miri.add_rustc_lib_path(builder);
169169
// Forward arguments.
170170
miri.arg("--").arg("--target").arg(target.rustc_target_arg());
171171
miri.args(builder.config.args());

‎src/bootstrap/src/core/build_steps/test.rs

+23-13
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::core::build_steps::llvm;
2020
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
2121
use crate::core::build_steps::tool::{self, SourceType, Tool};
2222
use crate::core::build_steps::toolstate::ToolState;
23+
use crate::core::builder;
2324
use crate::core::builder::crate_description;
2425
use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
2526
use crate::core::config::flags::get_completion;
@@ -380,7 +381,7 @@ impl Step for RustAnalyzer {
380381
// work in Rust CI
381382
cargo.env("SKIP_SLOW_TESTS", "1");
382383

383-
cargo.add_rustc_lib_path(builder, compiler);
384+
cargo.add_rustc_lib_path(builder);
384385
run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder);
385386
}
386387
}
@@ -426,7 +427,7 @@ impl Step for Rustfmt {
426427
t!(fs::create_dir_all(&dir));
427428
cargo.env("RUSTFMT_TEST_DIR", dir);
428429

429-
cargo.add_rustc_lib_path(builder, compiler);
430+
cargo.add_rustc_lib_path(builder);
430431

431432
run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder);
432433
}
@@ -476,7 +477,7 @@ impl Step for RustDemangler {
476477
t!(fs::create_dir_all(&dir));
477478

478479
cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
479-
cargo.add_rustc_lib_path(builder, compiler);
480+
cargo.add_rustc_lib_path(builder);
480481

481482
run_cargo_test(
482483
cargo,
@@ -517,7 +518,7 @@ impl Miri {
517518
SourceType::InTree,
518519
&[],
519520
);
520-
cargo.add_rustc_lib_path(builder, compiler);
521+
cargo.add_rustc_lib_path(builder);
521522
cargo.arg("--").arg("miri").arg("setup");
522523
cargo.arg("--target").arg(target.rustc_target_arg());
523524

@@ -618,7 +619,7 @@ impl Step for Miri {
618619
);
619620
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target);
620621

621-
cargo.add_rustc_lib_path(builder, compiler);
622+
cargo.add_rustc_lib_path(builder);
622623

623624
// miri tests need to know about the stage sysroot
624625
cargo.env("MIRI_SYSROOT", &miri_sysroot);
@@ -671,7 +672,7 @@ impl Step for Miri {
671672
SourceType::Submodule,
672673
&[],
673674
);
674-
cargo.add_rustc_lib_path(builder, compiler);
675+
cargo.add_rustc_lib_path(builder);
675676
cargo.arg("--").arg("miri").arg("test");
676677
if builder.config.locked_deps {
677678
cargo.arg("--locked");
@@ -788,7 +789,7 @@ impl Step for Clippy {
788789
let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
789790
cargo.env("HOST_LIBS", host_libs);
790791

791-
cargo.add_rustc_lib_path(builder, compiler);
792+
cargo.add_rustc_lib_path(builder);
792793
let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
793794

794795
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
@@ -2499,8 +2500,15 @@ impl Step for Crate {
24992500
// we're working with automatically.
25002501
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
25012502

2502-
let mut cargo =
2503-
builder.cargo(compiler, mode, SourceType::InTree, target, builder.kind.as_str(), false);
2503+
let mut cargo = builder::Cargo::new(
2504+
builder,
2505+
compiler,
2506+
mode,
2507+
SourceType::InTree,
2508+
target,
2509+
builder.kind.as_str(),
2510+
);
2511+
25042512
match mode {
25052513
Mode::Std => {
25062514
compile::std_cargo(builder, target, compiler.stage, &mut cargo);
@@ -3134,14 +3142,15 @@ impl Step for CodegenCranelift {
31343142
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
31353143

31363144
let build_cargo = || {
3137-
let mut cargo = builder.cargo(
3145+
let mut cargo = builder::Cargo::new(
3146+
builder,
31383147
compiler,
31393148
Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
31403149
SourceType::InTree,
31413150
target,
31423151
"run",
3143-
false,
31443152
);
3153+
31453154
cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
31463155
cargo
31473156
.arg("--manifest-path")
@@ -3261,14 +3270,15 @@ impl Step for CodegenGCC {
32613270
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
32623271

32633272
let build_cargo = || {
3264-
let mut cargo = builder.cargo(
3273+
let mut cargo = builder::Cargo::new(
3274+
builder,
32653275
compiler,
32663276
Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
32673277
SourceType::InTree,
32683278
target,
32693279
"run",
3270-
false,
32713280
);
3281+
32723282
cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
32733283
cargo
32743284
.arg("--manifest-path")

‎src/bootstrap/src/core/build_steps/tool.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::process::Command;
55

66
use crate::core::build_steps::compile;
77
use crate::core::build_steps::toolstate::ToolState;
8+
use crate::core::builder;
89
use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
910
use crate::core::config::TargetSelection;
1011
use crate::utils::channel::GitInfo;
@@ -142,7 +143,8 @@ pub fn prepare_tool_cargo(
142143
source_type: SourceType,
143144
extra_features: &[String],
144145
) -> CargoCommand {
145-
let mut cargo = builder.cargo(compiler, mode, source_type, target, command, false);
146+
let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, command);
147+
146148
let dir = builder.src.join(path);
147149
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
148150

‎src/bootstrap/src/core/builder.rs

+168-147
Original file line numberDiff line numberDiff line change
@@ -1299,21 +1299,18 @@ impl<'a> Builder<'a> {
12991299
cargo
13001300
}
13011301

1302-
/// Prepares an invocation of `cargo` to be run.
1303-
///
13041302
/// This will create a `Command` that represents a pending execution of
13051303
/// Cargo. This cargo will be configured to use `compiler` as the actual
13061304
/// rustc compiler, its output will be scoped by `mode`'s output directory,
13071305
/// it will pass the `--target` flag for the specified `target`, and will be
13081306
/// executing the Cargo command `cmd`.
1309-
pub fn cargo(
1307+
fn cargo(
13101308
&self,
13111309
compiler: Compiler,
13121310
mode: Mode,
13131311
source_type: SourceType,
13141312
target: TargetSelection,
13151313
cmd: &str,
1316-
is_for_mir_opt_tests: bool,
13171314
) -> Cargo {
13181315
let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
13191316
let out_dir = self.stage_out(compiler, mode);
@@ -1873,17 +1870,6 @@ impl<'a> Builder<'a> {
18731870
rustflags.arg("-Wrustc::internal");
18741871
}
18751872

1876-
if !is_for_mir_opt_tests {
1877-
self.configure_linker(
1878-
compiler,
1879-
target,
1880-
&mut cargo,
1881-
&mut rustflags,
1882-
&mut rustdocflags,
1883-
&mut hostflags,
1884-
);
1885-
}
1886-
18871873
// If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
18881874
// when compiling the standard library, since this might be linked into the final outputs
18891875
// produced by rustc. Since this mitigation is only available on Windows, only enable it
@@ -2032,136 +2018,14 @@ impl<'a> Builder<'a> {
20322018
cargo.env("RUSTFLAGS", &rustc_args.join(" "));
20332019
}
20342020

2035-
Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features }
2036-
}
2037-
2038-
fn configure_linker(
2039-
&self,
2040-
compiler: Compiler,
2041-
target: TargetSelection,
2042-
cargo: &mut Command,
2043-
rustflags: &mut Rustflags,
2044-
rustdocflags: &mut Rustflags,
2045-
hostflags: &mut HostFlags,
2046-
) {
2047-
// Dealing with rpath here is a little special, so let's go into some
2048-
// detail. First off, `-rpath` is a linker option on Unix platforms
2049-
// which adds to the runtime dynamic loader path when looking for
2050-
// dynamic libraries. We use this by default on Unix platforms to ensure
2051-
// that our nightlies behave the same on Windows, that is they work out
2052-
// of the box. This can be disabled by setting `rpath = false` in `[rust]`
2053-
// table of `config.toml`
2054-
//
2055-
// Ok, so the astute might be wondering "why isn't `-C rpath` used
2056-
// here?" and that is indeed a good question to ask. This codegen
2057-
// option is the compiler's current interface to generating an rpath.
2058-
// Unfortunately it doesn't quite suffice for us. The flag currently
2059-
// takes no value as an argument, so the compiler calculates what it
2060-
// should pass to the linker as `-rpath`. This unfortunately is based on
2061-
// the **compile time** directory structure which when building with
2062-
// Cargo will be very different than the runtime directory structure.
2063-
//
2064-
// All that's a really long winded way of saying that if we use
2065-
// `-Crpath` then the executables generated have the wrong rpath of
2066-
// something like `$ORIGIN/deps` when in fact the way we distribute
2067-
// rustc requires the rpath to be `$ORIGIN/../lib`.
2068-
//
2069-
// So, all in all, to set up the correct rpath we pass the linker
2070-
// argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
2071-
// fun to pass a flag to a tool to pass a flag to pass a flag to a tool
2072-
// to change a flag in a binary?
2073-
if self.config.rpath_enabled(target) && helpers::use_host_linker(target) {
2074-
let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap();
2075-
let rpath = if target.contains("apple") {
2076-
// Note that we need to take one extra step on macOS to also pass
2077-
// `-Wl,-instal_name,@rpath/...` to get things to work right. To
2078-
// do that we pass a weird flag to the compiler to get it to do
2079-
// so. Note that this is definitely a hack, and we should likely
2080-
// flesh out rpath support more fully in the future.
2081-
rustflags.arg("-Zosx-rpath-install-name");
2082-
Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
2083-
} else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
2084-
rustflags.arg("-Clink-args=-Wl,-z,origin");
2085-
Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
2086-
} else {
2087-
None
2088-
};
2089-
if let Some(rpath) = rpath {
2090-
rustflags.arg(&format!("-Clink-args={rpath}"));
2091-
}
2092-
}
2093-
2094-
for arg in linker_args(self, compiler.host, LldThreads::Yes) {
2095-
hostflags.arg(&arg);
2096-
}
2097-
2098-
if let Some(target_linker) = self.linker(target) {
2099-
let target = crate::envify(&target.triple);
2100-
cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
2101-
}
2102-
// We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
2103-
// `linker_args` here.
2104-
for flag in linker_flags(self, target, LldThreads::Yes) {
2105-
rustflags.arg(&flag);
2106-
}
2107-
for arg in linker_args(self, target, LldThreads::Yes) {
2108-
rustdocflags.arg(&arg);
2109-
}
2110-
2111-
if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
2112-
{
2113-
rustflags.arg("-Clink-arg=-gz");
2114-
}
2115-
2116-
// Throughout the build Cargo can execute a number of build scripts
2117-
// compiling C/C++ code and we need to pass compilers, archivers, flags, etc
2118-
// obtained previously to those build scripts.
2119-
// Build scripts use either the `cc` crate or `configure/make` so we pass
2120-
// the options through environment variables that are fetched and understood by both.
2121-
//
2122-
// FIXME: the guard against msvc shouldn't need to be here
2123-
if target.is_msvc() {
2124-
if let Some(ref cl) = self.config.llvm_clang_cl {
2125-
cargo.env("CC", cl).env("CXX", cl);
2126-
}
2127-
} else {
2128-
let ccache = self.config.ccache.as_ref();
2129-
let ccacheify = |s: &Path| {
2130-
let ccache = match ccache {
2131-
Some(ref s) => s,
2132-
None => return s.display().to_string(),
2133-
};
2134-
// FIXME: the cc-rs crate only recognizes the literal strings
2135-
// `ccache` and `sccache` when doing caching compilations, so we
2136-
// mirror that here. It should probably be fixed upstream to
2137-
// accept a new env var or otherwise work with custom ccache
2138-
// vars.
2139-
match &ccache[..] {
2140-
"ccache" | "sccache" => format!("{} {}", ccache, s.display()),
2141-
_ => s.display().to_string(),
2142-
}
2143-
};
2144-
let triple_underscored = target.triple.replace("-", "_");
2145-
let cc = ccacheify(&self.cc(target));
2146-
cargo.env(format!("CC_{triple_underscored}"), &cc);
2147-
2148-
let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
2149-
cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags);
2150-
2151-
if let Some(ar) = self.ar(target) {
2152-
let ranlib = format!("{} s", ar.display());
2153-
cargo
2154-
.env(format!("AR_{triple_underscored}"), ar)
2155-
.env(format!("RANLIB_{triple_underscored}"), ranlib);
2156-
}
2157-
2158-
if let Ok(cxx) = self.cxx(target) {
2159-
let cxx = ccacheify(&cxx);
2160-
let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
2161-
cargo
2162-
.env(format!("CXX_{triple_underscored}"), &cxx)
2163-
.env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
2164-
}
2021+
Cargo {
2022+
command: cargo,
2023+
compiler,
2024+
target,
2025+
rustflags,
2026+
rustdocflags,
2027+
hostflags,
2028+
allow_features,
21652029
}
21662030
}
21672031

@@ -2364,17 +2228,46 @@ impl HostFlags {
23642228
#[derive(Debug)]
23652229
pub struct Cargo {
23662230
command: Command,
2231+
compiler: Compiler,
2232+
target: TargetSelection,
23672233
rustflags: Rustflags,
23682234
rustdocflags: Rustflags,
23692235
hostflags: HostFlags,
23702236
allow_features: String,
23712237
}
23722238

23732239
impl Cargo {
2240+
/// Calls `Builder::cargo` and `Cargo::configure_linker` to prepare an invocation of `cargo` to be run.
2241+
pub fn new(
2242+
builder: &Builder<'_>,
2243+
compiler: Compiler,
2244+
mode: Mode,
2245+
source_type: SourceType,
2246+
target: TargetSelection,
2247+
cmd: &str,
2248+
) -> Cargo {
2249+
let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd);
2250+
cargo.configure_linker(builder);
2251+
cargo
2252+
}
2253+
2254+
/// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker`
2255+
pub fn new_for_mir_opt_tests(
2256+
builder: &Builder<'_>,
2257+
compiler: Compiler,
2258+
mode: Mode,
2259+
source_type: SourceType,
2260+
target: TargetSelection,
2261+
cmd: &str,
2262+
) -> Cargo {
2263+
builder.cargo(compiler, mode, source_type, target, cmd)
2264+
}
2265+
23742266
pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
23752267
self.rustdocflags.arg(arg);
23762268
self
23772269
}
2270+
23782271
pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
23792272
self.rustflags.arg(arg);
23802273
self
@@ -2404,8 +2297,8 @@ impl Cargo {
24042297
self
24052298
}
24062299

2407-
pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
2408-
builder.add_rustc_lib_path(compiler, &mut self.command);
2300+
pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>) {
2301+
builder.add_rustc_lib_path(self.compiler, &mut self.command);
24092302
}
24102303

24112304
pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
@@ -2424,6 +2317,134 @@ impl Cargo {
24242317
self.allow_features.push_str(features);
24252318
self
24262319
}
2320+
2321+
fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
2322+
let target = self.target;
2323+
let compiler = self.compiler;
2324+
2325+
// Dealing with rpath here is a little special, so let's go into some
2326+
// detail. First off, `-rpath` is a linker option on Unix platforms
2327+
// which adds to the runtime dynamic loader path when looking for
2328+
// dynamic libraries. We use this by default on Unix platforms to ensure
2329+
// that our nightlies behave the same on Windows, that is they work out
2330+
// of the box. This can be disabled by setting `rpath = false` in `[rust]`
2331+
// table of `config.toml`
2332+
//
2333+
// Ok, so the astute might be wondering "why isn't `-C rpath` used
2334+
// here?" and that is indeed a good question to ask. This codegen
2335+
// option is the compiler's current interface to generating an rpath.
2336+
// Unfortunately it doesn't quite suffice for us. The flag currently
2337+
// takes no value as an argument, so the compiler calculates what it
2338+
// should pass to the linker as `-rpath`. This unfortunately is based on
2339+
// the **compile time** directory structure which when building with
2340+
// Cargo will be very different than the runtime directory structure.
2341+
//
2342+
// All that's a really long winded way of saying that if we use
2343+
// `-Crpath` then the executables generated have the wrong rpath of
2344+
// something like `$ORIGIN/deps` when in fact the way we distribute
2345+
// rustc requires the rpath to be `$ORIGIN/../lib`.
2346+
//
2347+
// So, all in all, to set up the correct rpath we pass the linker
2348+
// argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
2349+
// fun to pass a flag to a tool to pass a flag to pass a flag to a tool
2350+
// to change a flag in a binary?
2351+
if builder.config.rpath_enabled(target) && helpers::use_host_linker(target) {
2352+
let libdir = builder.sysroot_libdir_relative(compiler).to_str().unwrap();
2353+
let rpath = if target.contains("apple") {
2354+
// Note that we need to take one extra step on macOS to also pass
2355+
// `-Wl,-instal_name,@rpath/...` to get things to work right. To
2356+
// do that we pass a weird flag to the compiler to get it to do
2357+
// so. Note that this is definitely a hack, and we should likely
2358+
// flesh out rpath support more fully in the future.
2359+
self.rustflags.arg("-Zosx-rpath-install-name");
2360+
Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
2361+
} else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
2362+
self.rustflags.arg("-Clink-args=-Wl,-z,origin");
2363+
Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
2364+
} else {
2365+
None
2366+
};
2367+
if let Some(rpath) = rpath {
2368+
self.rustflags.arg(&format!("-Clink-args={rpath}"));
2369+
}
2370+
}
2371+
2372+
for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
2373+
self.hostflags.arg(&arg);
2374+
}
2375+
2376+
if let Some(target_linker) = builder.linker(target) {
2377+
let target = crate::envify(&target.triple);
2378+
self.command.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
2379+
}
2380+
// We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
2381+
// `linker_args` here.
2382+
for flag in linker_flags(builder, target, LldThreads::Yes) {
2383+
self.rustflags.arg(&flag);
2384+
}
2385+
for arg in linker_args(builder, target, LldThreads::Yes) {
2386+
self.rustdocflags.arg(&arg);
2387+
}
2388+
2389+
if !builder.config.dry_run()
2390+
&& builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
2391+
{
2392+
self.rustflags.arg("-Clink-arg=-gz");
2393+
}
2394+
2395+
// Throughout the build Cargo can execute a number of build scripts
2396+
// compiling C/C++ code and we need to pass compilers, archivers, flags, etc
2397+
// obtained previously to those build scripts.
2398+
// Build scripts use either the `cc` crate or `configure/make` so we pass
2399+
// the options through environment variables that are fetched and understood by both.
2400+
//
2401+
// FIXME: the guard against msvc shouldn't need to be here
2402+
if target.is_msvc() {
2403+
if let Some(ref cl) = builder.config.llvm_clang_cl {
2404+
self.command.env("CC", cl).env("CXX", cl);
2405+
}
2406+
} else {
2407+
let ccache = builder.config.ccache.as_ref();
2408+
let ccacheify = |s: &Path| {
2409+
let ccache = match ccache {
2410+
Some(ref s) => s,
2411+
None => return s.display().to_string(),
2412+
};
2413+
// FIXME: the cc-rs crate only recognizes the literal strings
2414+
// `ccache` and `sccache` when doing caching compilations, so we
2415+
// mirror that here. It should probably be fixed upstream to
2416+
// accept a new env var or otherwise work with custom ccache
2417+
// vars.
2418+
match &ccache[..] {
2419+
"ccache" | "sccache" => format!("{} {}", ccache, s.display()),
2420+
_ => s.display().to_string(),
2421+
}
2422+
};
2423+
let triple_underscored = target.triple.replace("-", "_");
2424+
let cc = ccacheify(&builder.cc(target));
2425+
self.command.env(format!("CC_{triple_underscored}"), &cc);
2426+
2427+
let cflags = builder.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
2428+
self.command.env(format!("CFLAGS_{triple_underscored}"), &cflags);
2429+
2430+
if let Some(ar) = builder.ar(target) {
2431+
let ranlib = format!("{} s", ar.display());
2432+
self.command
2433+
.env(format!("AR_{triple_underscored}"), ar)
2434+
.env(format!("RANLIB_{triple_underscored}"), ranlib);
2435+
}
2436+
2437+
if let Ok(cxx) = builder.cxx(target) {
2438+
let cxx = ccacheify(&cxx);
2439+
let cxxflags = builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
2440+
self.command
2441+
.env(format!("CXX_{triple_underscored}"), &cxx)
2442+
.env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
2443+
}
2444+
}
2445+
2446+
self
2447+
}
24272448
}
24282449

24292450
impl From<Cargo> for Command {

0 commit comments

Comments
 (0)
Please sign in to comment.