diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 5f0afdb1b36ca..4a04dbf44aa6c 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -4,7 +4,9 @@ use crate::core::build_steps::compile::{ add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, }; use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType}; -use crate::core::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::core::builder::{ + self, crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step, +}; use crate::core::config::TargetSelection; use crate::utils::cache::Interned; use crate::INTERNER; @@ -110,13 +112,15 @@ impl Step for Std { let target = self.target; let compiler = builder.compiler(builder.top_stage, builder.config.build); - let mut cargo = builder.cargo( + let mut cargo = builder::Cargo::new( + builder, compiler, Mode::Std, SourceType::InTree, target, cargo_subcommand(builder.kind), ); + std_cargo(builder, target, compiler.stage, &mut cargo); if matches!(builder.config.cmd, Subcommand::Fix { .. }) { // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot. @@ -162,7 +166,8 @@ impl Step for Std { // since we initialize with an empty sysroot. // // Currently only the "libtest" tree of crates does this. - let mut cargo = builder.cargo( + let mut cargo = builder::Cargo::new( + builder, compiler, Mode::Std, SourceType::InTree, @@ -256,13 +261,15 @@ impl Step for Rustc { builder.ensure(Std::new(target)); } - let mut cargo = builder.cargo( + let mut cargo = builder::Cargo::new( + builder, compiler, Mode::Rustc, SourceType::InTree, target, cargo_subcommand(builder.kind), ); + rustc_cargo(builder, &mut cargo, target, compiler.stage); // For ./x.py clippy, don't run with --all-targets because @@ -332,13 +339,15 @@ impl Step for CodegenBackend { builder.ensure(Rustc::new(target, builder)); - let mut cargo = builder.cargo( + let mut cargo = builder::Cargo::new( + builder, compiler, Mode::Codegen, SourceType::InTree, target, cargo_subcommand(builder.kind), ); + cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 27b1d311864f3..64bef2d301582 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -22,6 +22,7 @@ use serde_derive::Deserialize; use crate::core::build_steps::dist; use crate::core::build_steps::llvm; use crate::core::build_steps::tool::SourceType; +use crate::core::builder; use crate::core::builder::crate_description; use crate::core::builder::Cargo; use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; @@ -239,12 +240,26 @@ impl Step for Std { // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the // fact that this is a check build integrates nicely with run_cargo. let mut cargo = if self.is_for_mir_opt_tests { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "check"); + let mut cargo = builder::Cargo::new_for_mir_opt_tests( + builder, + compiler, + Mode::Std, + SourceType::InTree, + target, + "check", + ); cargo.rustflag("-Zalways-encode-mir"); cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml")); cargo } else { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build"); + let mut cargo = builder::Cargo::new( + builder, + compiler, + Mode::Std, + SourceType::InTree, + target, + "build", + ); std_cargo(builder, target, compiler.stage, &mut cargo); for krate in &*self.crates { cargo.arg("-p").arg(krate); @@ -913,7 +928,15 @@ impl Step for Rustc { builder.config.build, )); - let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build"); + let mut cargo = builder::Cargo::new( + builder, + compiler, + Mode::Rustc, + SourceType::InTree, + target, + "build", + ); + rustc_cargo(builder, &mut cargo, target, compiler.stage); if builder.config.rust_profile_use.is_some() @@ -1333,7 +1356,14 @@ impl Step for CodegenBackend { let out_dir = builder.cargo_out(compiler, Mode::Codegen, target); - let mut cargo = builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build"); + let mut cargo = builder::Cargo::new( + builder, + compiler, + Mode::Codegen, + SourceType::InTree, + target, + "build", + ); cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 57e63927c95e1..fdb099e4ab1d7 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -13,7 +13,7 @@ use std::{fs, mem}; use crate::core::build_steps::compile; use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool}; -use crate::core::builder::crate_description; +use crate::core::builder::{self, crate_description}; use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; use crate::utils::cache::{Interned, INTERNER}; @@ -684,7 +684,9 @@ fn doc_std( // as a function parameter. let out_dir = target_dir.join(target.triple).join("doc"); - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "doc"); + let mut cargo = + builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, "doc"); + compile::std_cargo(builder, target, compiler.stage, &mut cargo); cargo .arg("--no-deps") @@ -785,7 +787,9 @@ impl Step for Rustc { ); // Build cargo command. - let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc"); + let mut cargo = + builder::Cargo::new(builder, compiler, Mode::Rustc, SourceType::InTree, target, "doc"); + cargo.rustdocflag("--document-private-items"); // Since we always pass --document-private-items, there's no need to warn about linking to private items. cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index d9e0da14a70ba..5fa5f2d47946a 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -165,7 +165,7 @@ impl Step for Miri { SourceType::InTree, &[], ); - miri.add_rustc_lib_path(builder, compiler); + miri.add_rustc_lib_path(builder); // Forward arguments. miri.arg("--").arg("--target").arg(target.rustc_target_arg()); miri.args(builder.config.args()); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index baf1b5a4a1afd..1dbda405128ab 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -20,6 +20,7 @@ use crate::core::build_steps::llvm; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{self, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; +use crate::core::builder; use crate::core::builder::crate_description; use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; @@ -380,7 +381,7 @@ impl Step for RustAnalyzer { // work in Rust CI cargo.env("SKIP_SLOW_TESTS", "1"); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder); } } @@ -426,7 +427,7 @@ impl Step for Rustfmt { t!(fs::create_dir_all(&dir)); cargo.env("RUSTFMT_TEST_DIR", dir); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder); } @@ -476,7 +477,7 @@ impl Step for RustDemangler { t!(fs::create_dir_all(&dir)); cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); run_cargo_test( cargo, @@ -517,7 +518,7 @@ impl Miri { SourceType::InTree, &[], ); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); cargo.arg("--").arg("miri").arg("setup"); cargo.arg("--target").arg(target.rustc_target_arg()); @@ -618,7 +619,7 @@ impl Step for Miri { ); let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); @@ -671,7 +672,7 @@ impl Step for Miri { SourceType::Submodule, &[], ); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); cargo.arg("--").arg("miri").arg("test"); if builder.config.locked_deps { cargo.arg("--locked"); @@ -788,7 +789,7 @@ impl Step for Clippy { let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir()); cargo.env("HOST_LIBS", host_libs); - cargo.add_rustc_lib_path(builder, compiler); + cargo.add_rustc_lib_path(builder); let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); @@ -2499,8 +2500,15 @@ impl Step for Crate { // we're working with automatically. let compiler = builder.compiler_for(compiler.stage, compiler.host, target); - let mut cargo = - builder.cargo(compiler, mode, SourceType::InTree, target, builder.kind.as_str()); + let mut cargo = builder::Cargo::new( + builder, + compiler, + mode, + SourceType::InTree, + target, + builder.kind.as_str(), + ); + match mode { Mode::Std => { compile::std_cargo(builder, target, compiler.stage, &mut cargo); @@ -3134,13 +3142,15 @@ impl Step for CodegenCranelift { let compiler = builder.compiler_for(compiler.stage, compiler.host, target); let build_cargo = || { - let mut cargo = builder.cargo( + let mut cargo = builder::Cargo::new( + builder, compiler, Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works SourceType::InTree, target, "run", ); + cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift")); cargo .arg("--manifest-path") @@ -3260,13 +3270,15 @@ impl Step for CodegenGCC { let compiler = builder.compiler_for(compiler.stage, compiler.host, target); let build_cargo = || { - let mut cargo = builder.cargo( + let mut cargo = builder::Cargo::new( + builder, compiler, Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works SourceType::InTree, target, "run", ); + cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc")); cargo .arg("--manifest-path") diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 5d8d10a7debc3..a3daf22c9a99d 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -5,6 +5,7 @@ use std::process::Command; use crate::core::build_steps::compile; use crate::core::build_steps::toolstate::ToolState; +use crate::core::builder; use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; @@ -142,7 +143,8 @@ pub fn prepare_tool_cargo( source_type: SourceType, extra_features: &[String], ) -> CargoCommand { - let mut cargo = builder.cargo(compiler, mode, source_type, target, command); + let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, command); + let dir = builder.src.join(path); cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 83485abfa5618..b21ffe868e145 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1299,14 +1299,12 @@ impl<'a> Builder<'a> { cargo } - /// Prepares an invocation of `cargo` to be run. - /// /// This will create a `Command` that represents a pending execution of /// Cargo. This cargo will be configured to use `compiler` as the actual /// rustc compiler, its output will be scoped by `mode`'s output directory, /// it will pass the `--target` flag for the specified `target`, and will be /// executing the Cargo command `cmd`. - pub fn cargo( + fn cargo( &self, compiler: Compiler, mode: Mode, @@ -1872,17 +1870,6 @@ impl<'a> Builder<'a> { rustflags.arg("-Wrustc::internal"); } - if cmd != "check" { - self.configure_linker( - compiler, - target, - &mut cargo, - &mut rustflags, - &mut rustdocflags, - &mut hostflags, - ); - } - // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc // when compiling the standard library, since this might be linked into the final outputs // produced by rustc. Since this mitigation is only available on Windows, only enable it @@ -2031,136 +2018,14 @@ impl<'a> Builder<'a> { cargo.env("RUSTFLAGS", &rustc_args.join(" ")); } - Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features } - } - - fn configure_linker( - &self, - compiler: Compiler, - target: TargetSelection, - cargo: &mut Command, - rustflags: &mut Rustflags, - rustdocflags: &mut Rustflags, - hostflags: &mut HostFlags, - ) { - // Dealing with rpath here is a little special, so let's go into some - // detail. First off, `-rpath` is a linker option on Unix platforms - // which adds to the runtime dynamic loader path when looking for - // dynamic libraries. We use this by default on Unix platforms to ensure - // that our nightlies behave the same on Windows, that is they work out - // of the box. This can be disabled by setting `rpath = false` in `[rust]` - // table of `config.toml` - // - // Ok, so the astute might be wondering "why isn't `-C rpath` used - // here?" and that is indeed a good question to ask. This codegen - // option is the compiler's current interface to generating an rpath. - // Unfortunately it doesn't quite suffice for us. The flag currently - // takes no value as an argument, so the compiler calculates what it - // should pass to the linker as `-rpath`. This unfortunately is based on - // the **compile time** directory structure which when building with - // Cargo will be very different than the runtime directory structure. - // - // All that's a really long winded way of saying that if we use - // `-Crpath` then the executables generated have the wrong rpath of - // something like `$ORIGIN/deps` when in fact the way we distribute - // rustc requires the rpath to be `$ORIGIN/../lib`. - // - // So, all in all, to set up the correct rpath we pass the linker - // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it - // fun to pass a flag to a tool to pass a flag to pass a flag to a tool - // to change a flag in a binary? - if self.config.rpath_enabled(target) && helpers::use_host_linker(target) { - let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap(); - let rpath = if target.contains("apple") { - // Note that we need to take one extra step on macOS to also pass - // `-Wl,-instal_name,@rpath/...` to get things to work right. To - // do that we pass a weird flag to the compiler to get it to do - // so. Note that this is definitely a hack, and we should likely - // flesh out rpath support more fully in the future. - rustflags.arg("-Zosx-rpath-install-name"); - Some(format!("-Wl,-rpath,@loader_path/../{libdir}")) - } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") { - rustflags.arg("-Clink-args=-Wl,-z,origin"); - Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}")) - } else { - None - }; - if let Some(rpath) = rpath { - rustflags.arg(&format!("-Clink-args={rpath}")); - } - } - - for arg in linker_args(self, compiler.host, LldThreads::Yes) { - hostflags.arg(&arg); - } - - if let Some(target_linker) = self.linker(target) { - let target = crate::envify(&target.triple); - cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker); - } - // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not - // `linker_args` here. - for flag in linker_flags(self, target, LldThreads::Yes) { - rustflags.arg(&flag); - } - for arg in linker_args(self, target, LldThreads::Yes) { - rustdocflags.arg(&arg); - } - - if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz") - { - rustflags.arg("-Clink-arg=-gz"); - } - - // Throughout the build Cargo can execute a number of build scripts - // compiling C/C++ code and we need to pass compilers, archivers, flags, etc - // obtained previously to those build scripts. - // Build scripts use either the `cc` crate or `configure/make` so we pass - // the options through environment variables that are fetched and understood by both. - // - // FIXME: the guard against msvc shouldn't need to be here - if target.is_msvc() { - if let Some(ref cl) = self.config.llvm_clang_cl { - cargo.env("CC", cl).env("CXX", cl); - } - } else { - let ccache = self.config.ccache.as_ref(); - let ccacheify = |s: &Path| { - let ccache = match ccache { - Some(ref s) => s, - None => return s.display().to_string(), - }; - // FIXME: the cc-rs crate only recognizes the literal strings - // `ccache` and `sccache` when doing caching compilations, so we - // mirror that here. It should probably be fixed upstream to - // accept a new env var or otherwise work with custom ccache - // vars. - match &ccache[..] { - "ccache" | "sccache" => format!("{} {}", ccache, s.display()), - _ => s.display().to_string(), - } - }; - let triple_underscored = target.triple.replace("-", "_"); - let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{triple_underscored}"), &cc); - - let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" "); - cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags); - - if let Some(ar) = self.ar(target) { - let ranlib = format!("{} s", ar.display()); - cargo - .env(format!("AR_{triple_underscored}"), ar) - .env(format!("RANLIB_{triple_underscored}"), ranlib); - } - - if let Ok(cxx) = self.cxx(target) { - let cxx = ccacheify(&cxx); - let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "); - cargo - .env(format!("CXX_{triple_underscored}"), &cxx) - .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags); - } + Cargo { + command: cargo, + compiler, + target, + rustflags, + rustdocflags, + hostflags, + allow_features, } } @@ -2363,6 +2228,8 @@ impl HostFlags { #[derive(Debug)] pub struct Cargo { command: Command, + compiler: Compiler, + target: TargetSelection, rustflags: Rustflags, rustdocflags: Rustflags, hostflags: HostFlags, @@ -2370,10 +2237,37 @@ pub struct Cargo { } impl Cargo { + /// Calls `Builder::cargo` and `Cargo::configure_linker` to prepare an invocation of `cargo` to be run. + pub fn new( + builder: &Builder<'_>, + compiler: Compiler, + mode: Mode, + source_type: SourceType, + target: TargetSelection, + cmd: &str, + ) -> Cargo { + let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd); + cargo.configure_linker(builder); + cargo + } + + /// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker` + pub fn new_for_mir_opt_tests( + builder: &Builder<'_>, + compiler: Compiler, + mode: Mode, + source_type: SourceType, + target: TargetSelection, + cmd: &str, + ) -> Cargo { + builder.cargo(compiler, mode, source_type, target, cmd) + } + pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo { self.rustdocflags.arg(arg); self } + pub fn rustflag(&mut self, arg: &str) -> &mut Cargo { self.rustflags.arg(arg); self @@ -2403,8 +2297,8 @@ impl Cargo { self } - pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) { - builder.add_rustc_lib_path(compiler, &mut self.command); + pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>) { + builder.add_rustc_lib_path(self.compiler, &mut self.command); } pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo { @@ -2423,6 +2317,134 @@ impl Cargo { self.allow_features.push_str(features); self } + + fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo { + let target = self.target; + let compiler = self.compiler; + + // Dealing with rpath here is a little special, so let's go into some + // detail. First off, `-rpath` is a linker option on Unix platforms + // which adds to the runtime dynamic loader path when looking for + // dynamic libraries. We use this by default on Unix platforms to ensure + // that our nightlies behave the same on Windows, that is they work out + // of the box. This can be disabled by setting `rpath = false` in `[rust]` + // table of `config.toml` + // + // Ok, so the astute might be wondering "why isn't `-C rpath` used + // here?" and that is indeed a good question to ask. This codegen + // option is the compiler's current interface to generating an rpath. + // Unfortunately it doesn't quite suffice for us. The flag currently + // takes no value as an argument, so the compiler calculates what it + // should pass to the linker as `-rpath`. This unfortunately is based on + // the **compile time** directory structure which when building with + // Cargo will be very different than the runtime directory structure. + // + // All that's a really long winded way of saying that if we use + // `-Crpath` then the executables generated have the wrong rpath of + // something like `$ORIGIN/deps` when in fact the way we distribute + // rustc requires the rpath to be `$ORIGIN/../lib`. + // + // So, all in all, to set up the correct rpath we pass the linker + // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it + // fun to pass a flag to a tool to pass a flag to pass a flag to a tool + // to change a flag in a binary? + if builder.config.rpath_enabled(target) && helpers::use_host_linker(target) { + let libdir = builder.sysroot_libdir_relative(compiler).to_str().unwrap(); + let rpath = if target.contains("apple") { + // Note that we need to take one extra step on macOS to also pass + // `-Wl,-instal_name,@rpath/...` to get things to work right. To + // do that we pass a weird flag to the compiler to get it to do + // so. Note that this is definitely a hack, and we should likely + // flesh out rpath support more fully in the future. + self.rustflags.arg("-Zosx-rpath-install-name"); + Some(format!("-Wl,-rpath,@loader_path/../{libdir}")) + } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") { + self.rustflags.arg("-Clink-args=-Wl,-z,origin"); + Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}")) + } else { + None + }; + if let Some(rpath) = rpath { + self.rustflags.arg(&format!("-Clink-args={rpath}")); + } + } + + for arg in linker_args(builder, compiler.host, LldThreads::Yes) { + self.hostflags.arg(&arg); + } + + if let Some(target_linker) = builder.linker(target) { + let target = crate::envify(&target.triple); + self.command.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker); + } + // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not + // `linker_args` here. + for flag in linker_flags(builder, target, LldThreads::Yes) { + self.rustflags.arg(&flag); + } + for arg in linker_args(builder, target, LldThreads::Yes) { + self.rustdocflags.arg(&arg); + } + + if !builder.config.dry_run() + && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz") + { + self.rustflags.arg("-Clink-arg=-gz"); + } + + // Throughout the build Cargo can execute a number of build scripts + // compiling C/C++ code and we need to pass compilers, archivers, flags, etc + // obtained previously to those build scripts. + // Build scripts use either the `cc` crate or `configure/make` so we pass + // the options through environment variables that are fetched and understood by both. + // + // FIXME: the guard against msvc shouldn't need to be here + if target.is_msvc() { + if let Some(ref cl) = builder.config.llvm_clang_cl { + self.command.env("CC", cl).env("CXX", cl); + } + } else { + let ccache = builder.config.ccache.as_ref(); + let ccacheify = |s: &Path| { + let ccache = match ccache { + Some(ref s) => s, + None => return s.display().to_string(), + }; + // FIXME: the cc-rs crate only recognizes the literal strings + // `ccache` and `sccache` when doing caching compilations, so we + // mirror that here. It should probably be fixed upstream to + // accept a new env var or otherwise work with custom ccache + // vars. + match &ccache[..] { + "ccache" | "sccache" => format!("{} {}", ccache, s.display()), + _ => s.display().to_string(), + } + }; + let triple_underscored = target.triple.replace("-", "_"); + let cc = ccacheify(&builder.cc(target)); + self.command.env(format!("CC_{triple_underscored}"), &cc); + + let cflags = builder.cflags(target, GitRepo::Rustc, CLang::C).join(" "); + self.command.env(format!("CFLAGS_{triple_underscored}"), &cflags); + + if let Some(ar) = builder.ar(target) { + let ranlib = format!("{} s", ar.display()); + self.command + .env(format!("AR_{triple_underscored}"), ar) + .env(format!("RANLIB_{triple_underscored}"), ranlib); + } + + if let Ok(cxx) = builder.cxx(target) { + let cxx = ccacheify(&cxx); + let cxxflags = builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "); + self.command + .env(format!("CXX_{triple_underscored}"), &cxx) + .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags); + } + } + + self + } } impl From for Command {