Allow manually opting in and out of Linux linker overrides
This commit is contained in:
@@ -758,12 +758,8 @@
|
|||||||
# Currently, the only standard options supported here are `"llvm"`, `"cranelift"` and `"gcc"`.
|
# Currently, the only standard options supported here are `"llvm"`, `"cranelift"` and `"gcc"`.
|
||||||
#rust.codegen-backends = ["llvm"]
|
#rust.codegen-backends = ["llvm"]
|
||||||
|
|
||||||
# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and
|
# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute,
|
||||||
# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be
|
#rust.lld = false, except for targets that opt into LLD (see `target.default-linker-linux-override`)
|
||||||
# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from
|
|
||||||
# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will
|
|
||||||
# make this default to false.
|
|
||||||
#rust.lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true
|
|
||||||
|
|
||||||
# Indicates if we should override the linker used to link Rust crates during bootstrap to be LLD.
|
# Indicates if we should override the linker used to link Rust crates during bootstrap to be LLD.
|
||||||
# If set to `true` or `"external"`, a global `lld` binary that has to be in $PATH
|
# If set to `true` or `"external"`, a global `lld` binary that has to be in $PATH
|
||||||
@@ -1067,3 +1063,17 @@
|
|||||||
# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.
|
# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.
|
||||||
# This overrides the global `rust.jemalloc` option. See that option for more info.
|
# This overrides the global `rust.jemalloc` option. See that option for more info.
|
||||||
#jemalloc = rust.jemalloc (bool)
|
#jemalloc = rust.jemalloc (bool)
|
||||||
|
|
||||||
|
# The linker configuration that will *override* the default linker used for Linux
|
||||||
|
# targets in the built compiler.
|
||||||
|
#
|
||||||
|
# The following values are supported:
|
||||||
|
# - `off` => do not apply any override and use the default linker. This can be used to opt out of
|
||||||
|
# linker overrides set by bootstrap for specific targets (see below).
|
||||||
|
# - `self-contained-lld-cc` => override the default linker to be self-contained LLD (`rust-lld`)
|
||||||
|
# that is invoked through `cc`.
|
||||||
|
#
|
||||||
|
# Currently, the following targets automatically opt into the self-contained LLD linker, unless you
|
||||||
|
# pass `off`:
|
||||||
|
# - x86_64-unknown-linux-gnu
|
||||||
|
#default-linker-linux-override = "off" (for most targets)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use crate::core::builder;
|
|||||||
use crate::core::builder::{
|
use crate::core::builder::{
|
||||||
Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
|
Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
|
||||||
};
|
};
|
||||||
|
use crate::core::config::toml::target::DefaultLinuxLinkerOverride;
|
||||||
use crate::core::config::{
|
use crate::core::config::{
|
||||||
CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection,
|
CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection,
|
||||||
};
|
};
|
||||||
@@ -1355,9 +1356,14 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
|
|||||||
cargo.env("CFG_DEFAULT_LINKER", s);
|
cargo.env("CFG_DEFAULT_LINKER", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable rustc's env var for `rust-lld` when requested.
|
// Enable rustc's env var to use a linker override on Linux when requested.
|
||||||
if builder.config.lld_enabled {
|
if let Some(linker) = target_config.map(|c| c.default_linker_linux_override) {
|
||||||
cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1");
|
match linker {
|
||||||
|
DefaultLinuxLinkerOverride::Off => {}
|
||||||
|
DefaultLinuxLinkerOverride::SelfContainedLldCc => {
|
||||||
|
cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if builder.config.rust_verify_llvm_ir {
|
if builder.config.rust_verify_llvm_ir {
|
||||||
|
|||||||
@@ -514,7 +514,9 @@ mod snapshot {
|
|||||||
};
|
};
|
||||||
use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata};
|
use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata};
|
||||||
use crate::core::config::TargetSelection;
|
use crate::core::config::TargetSelection;
|
||||||
use crate::core::config::toml::rust::with_lld_opt_in_targets;
|
use crate::core::config::toml::target::{
|
||||||
|
DefaultLinuxLinkerOverride, with_default_linux_linker_overrides,
|
||||||
|
};
|
||||||
use crate::utils::cache::Cache;
|
use crate::utils::cache::Cache;
|
||||||
use crate::utils::helpers::get_host_target;
|
use crate::utils::helpers::get_host_target;
|
||||||
use crate::utils::tests::{ConfigBuilder, TestCtx};
|
use crate::utils::tests::{ConfigBuilder, TestCtx};
|
||||||
@@ -782,9 +784,11 @@ mod snapshot {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_compiler_lld_opt_in() {
|
fn build_compiler_lld_opt_in() {
|
||||||
with_lld_opt_in_targets(vec![host_target()], || {
|
with_default_linux_linker_overrides(
|
||||||
let ctx = TestCtx::new();
|
[(host_target(), DefaultLinuxLinkerOverride::SelfContainedLldCc)].into(),
|
||||||
insta::assert_snapshot!(
|
|| {
|
||||||
|
let ctx = TestCtx::new();
|
||||||
|
insta::assert_snapshot!(
|
||||||
ctx.config("build")
|
ctx.config("build")
|
||||||
.path("compiler")
|
.path("compiler")
|
||||||
.render_steps(), @r"
|
.render_steps(), @r"
|
||||||
@@ -792,7 +796,26 @@ mod snapshot {
|
|||||||
[build] rustc 0 <host> -> rustc 1 <host>
|
[build] rustc 0 <host> -> rustc 1 <host>
|
||||||
[build] rustc 0 <host> -> LldWrapper 1 <host>
|
[build] rustc 0 <host> -> LldWrapper 1 <host>
|
||||||
");
|
");
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_compiler_lld_opt_in_lld_disabled() {
|
||||||
|
with_default_linux_linker_overrides(
|
||||||
|
[(host_target(), DefaultLinuxLinkerOverride::SelfContainedLldCc)].into(),
|
||||||
|
|| {
|
||||||
|
let ctx = TestCtx::new();
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
ctx.config("build")
|
||||||
|
.path("compiler")
|
||||||
|
.args(&["--set", "rust.lld=false"])
|
||||||
|
.render_steps(), @r"
|
||||||
|
[build] llvm <host>
|
||||||
|
[build] rustc 0 <host> -> rustc 1 <host>
|
||||||
|
");
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -42,9 +42,11 @@ use crate::core::config::toml::install::Install;
|
|||||||
use crate::core::config::toml::llvm::Llvm;
|
use crate::core::config::toml::llvm::Llvm;
|
||||||
use crate::core::config::toml::rust::{
|
use crate::core::config::toml::rust::{
|
||||||
BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc,
|
BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc,
|
||||||
default_lld_opt_in_targets, parse_codegen_backends,
|
parse_codegen_backends,
|
||||||
|
};
|
||||||
|
use crate::core::config::toml::target::{
|
||||||
|
DefaultLinuxLinkerOverride, Target, TomlTarget, default_linux_linker_overrides,
|
||||||
};
|
};
|
||||||
use crate::core::config::toml::target::{Target, TomlTarget};
|
|
||||||
use crate::core::config::{
|
use crate::core::config::{
|
||||||
CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt,
|
CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt,
|
||||||
RustcLto, SplitDebuginfo, StringOrBool, threads_from_config,
|
RustcLto, SplitDebuginfo, StringOrBool, threads_from_config,
|
||||||
@@ -829,6 +831,11 @@ impl Config {
|
|||||||
.to_owned();
|
.to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut lld_enabled = rust_lld_enabled.unwrap_or(false);
|
||||||
|
|
||||||
|
// Linux targets for which the user explicitly overrode the used linker
|
||||||
|
let mut targets_with_user_linker_override = HashSet::new();
|
||||||
|
|
||||||
if let Some(t) = toml.target {
|
if let Some(t) = toml.target {
|
||||||
for (triple, cfg) in t {
|
for (triple, cfg) in t {
|
||||||
let TomlTarget {
|
let TomlTarget {
|
||||||
@@ -837,6 +844,7 @@ impl Config {
|
|||||||
ar: target_ar,
|
ar: target_ar,
|
||||||
ranlib: target_ranlib,
|
ranlib: target_ranlib,
|
||||||
default_linker: target_default_linker,
|
default_linker: target_default_linker,
|
||||||
|
default_linker_linux: target_default_linker_linux_override,
|
||||||
linker: target_linker,
|
linker: target_linker,
|
||||||
split_debuginfo: target_split_debuginfo,
|
split_debuginfo: target_split_debuginfo,
|
||||||
llvm_config: target_llvm_config,
|
llvm_config: target_llvm_config,
|
||||||
@@ -860,6 +868,33 @@ impl Config {
|
|||||||
|
|
||||||
let mut target = Target::from_triple(&triple);
|
let mut target = Target::from_triple(&triple);
|
||||||
|
|
||||||
|
if target_default_linker_linux_override.is_some() {
|
||||||
|
targets_with_user_linker_override.insert(triple.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_linker_linux_override = match target_default_linker_linux_override {
|
||||||
|
Some(DefaultLinuxLinkerOverride::SelfContainedLldCc) => {
|
||||||
|
if rust_default_linker.is_some() {
|
||||||
|
panic!(
|
||||||
|
"cannot set both `default-linker` and `default-linker-linux` for target `{triple}`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !triple.contains("linux-gnu") {
|
||||||
|
panic!(
|
||||||
|
"`default-linker-linux` can only be set for Linux GNU targets, not for `{triple}`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !lld_enabled {
|
||||||
|
panic!(
|
||||||
|
"Trying to override the default Linux linker for `{triple}` to be self-contained LLD, but LLD is not being built. Enable it with rust.lld = true."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
DefaultLinuxLinkerOverride::SelfContainedLldCc
|
||||||
|
}
|
||||||
|
Some(DefaultLinuxLinkerOverride::Off) => DefaultLinuxLinkerOverride::Off,
|
||||||
|
None => DefaultLinuxLinkerOverride::default(),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(ref s) = target_llvm_config {
|
if let Some(ref s) = target_llvm_config {
|
||||||
if download_rustc_commit.is_some() && triple == *host_target.triple {
|
if download_rustc_commit.is_some() && triple == *host_target.triple {
|
||||||
panic!(
|
panic!(
|
||||||
@@ -893,6 +928,7 @@ impl Config {
|
|||||||
target.linker = target_linker.map(PathBuf::from);
|
target.linker = target_linker.map(PathBuf::from);
|
||||||
target.crt_static = target_crt_static;
|
target.crt_static = target_crt_static;
|
||||||
target.default_linker = target_default_linker;
|
target.default_linker = target_default_linker;
|
||||||
|
target.default_linker_linux_override = default_linker_linux_override;
|
||||||
target.musl_root = target_musl_root.map(PathBuf::from);
|
target.musl_root = target_musl_root.map(PathBuf::from);
|
||||||
target.musl_libdir = target_musl_libdir.map(PathBuf::from);
|
target.musl_libdir = target_musl_libdir.map(PathBuf::from);
|
||||||
target.wasi_root = target_wasi_root.map(PathBuf::from);
|
target.wasi_root = target_wasi_root.map(PathBuf::from);
|
||||||
@@ -918,6 +954,38 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (target, linker_override) in default_linux_linker_overrides() {
|
||||||
|
// If the user overrode the default Linux linker, do not apply bootstrap defaults
|
||||||
|
if targets_with_user_linker_override.contains(&target) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let default_linux_linker_override = match linker_override {
|
||||||
|
DefaultLinuxLinkerOverride::Off => continue,
|
||||||
|
DefaultLinuxLinkerOverride::SelfContainedLldCc => {
|
||||||
|
// If we automatically default to the self-contained LLD linker,
|
||||||
|
// we also need to handle the rust.lld option.
|
||||||
|
match rust_lld_enabled {
|
||||||
|
// If LLD was not enabled explicitly, we enable it
|
||||||
|
None => {
|
||||||
|
lld_enabled = true;
|
||||||
|
Some(DefaultLinuxLinkerOverride::SelfContainedLldCc)
|
||||||
|
}
|
||||||
|
// If it was enabled already, we don't need to do anything
|
||||||
|
Some(true) => Some(DefaultLinuxLinkerOverride::SelfContainedLldCc),
|
||||||
|
// If it was explicitly disabled, we do not apply the
|
||||||
|
// linker override
|
||||||
|
Some(false) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(linker_override) = default_linux_linker_override {
|
||||||
|
target_config
|
||||||
|
.entry(TargetSelection::from_user(&target))
|
||||||
|
.or_default()
|
||||||
|
.default_linker_linux_override = linker_override;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let llvm_from_ci = parse_download_ci_llvm(
|
let llvm_from_ci = parse_download_ci_llvm(
|
||||||
&dwn_ctx,
|
&dwn_ctx,
|
||||||
&rust_info,
|
&rust_info,
|
||||||
@@ -926,28 +994,6 @@ impl Config {
|
|||||||
llvm_assertions,
|
llvm_assertions,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
|
|
||||||
// build our internal lld and use it as the default linker, by setting the `rust.lld` config
|
|
||||||
// to true by default:
|
|
||||||
// - on the `x86_64-unknown-linux-gnu` target
|
|
||||||
// - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
|
|
||||||
// we're also able to build the corresponding lld
|
|
||||||
// - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
|
|
||||||
// lld
|
|
||||||
// - otherwise, we'd be using an external llvm, and lld would not necessarily available and
|
|
||||||
// thus, disabled
|
|
||||||
// - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
|
|
||||||
// when the config sets `rust.lld = false`
|
|
||||||
let lld_enabled = if default_lld_opt_in_targets().contains(&host_target.triple.to_string())
|
|
||||||
&& hosts == [host_target]
|
|
||||||
{
|
|
||||||
let no_llvm_config =
|
|
||||||
target_config.get(&host_target).is_none_or(|config| config.llvm_config.is_none());
|
|
||||||
rust_lld_enabled.unwrap_or(llvm_from_ci || no_llvm_config)
|
|
||||||
} else {
|
|
||||||
rust_lld_enabled.unwrap_or(false)
|
|
||||||
};
|
|
||||||
|
|
||||||
if llvm_from_ci {
|
if llvm_from_ci {
|
||||||
let warn = |option: &str| {
|
let warn = |option: &str| {
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -438,28 +438,3 @@ pub(crate) fn parse_codegen_backends(
|
|||||||
}
|
}
|
||||||
found_backends
|
found_backends
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
pub fn default_lld_opt_in_targets() -> Vec<String> {
|
|
||||||
vec!["x86_64-unknown-linux-gnu".to_string()]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
thread_local! {
|
|
||||||
static TEST_LLD_OPT_IN_TARGETS: std::cell::RefCell<Option<Vec<String>>> = std::cell::RefCell::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn default_lld_opt_in_targets() -> Vec<String> {
|
|
||||||
TEST_LLD_OPT_IN_TARGETS.with(|cell| cell.borrow().clone()).unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn with_lld_opt_in_targets<R>(targets: Vec<String>, f: impl FnOnce() -> R) -> R {
|
|
||||||
TEST_LLD_OPT_IN_TARGETS.with(|cell| {
|
|
||||||
let prev = cell.replace(Some(targets));
|
|
||||||
let result = f();
|
|
||||||
cell.replace(prev);
|
|
||||||
result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
//! * [`Target`]: This struct represents the processed and validated configuration for a
|
//! * [`Target`]: This struct represents the processed and validated configuration for a
|
||||||
//! build target, which is is stored in the main `Config` structure.
|
//! build target, which is is stored in the main `Config` structure.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::de::Error;
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
use crate::core::config::{
|
use crate::core::config::{
|
||||||
@@ -24,6 +27,7 @@ define_config! {
|
|||||||
ar: Option<String> = "ar",
|
ar: Option<String> = "ar",
|
||||||
ranlib: Option<String> = "ranlib",
|
ranlib: Option<String> = "ranlib",
|
||||||
default_linker: Option<PathBuf> = "default-linker",
|
default_linker: Option<PathBuf> = "default-linker",
|
||||||
|
default_linker_linux: Option<DefaultLinuxLinkerOverride> = "default-linker-linux-override",
|
||||||
linker: Option<String> = "linker",
|
linker: Option<String> = "linker",
|
||||||
split_debuginfo: Option<String> = "split-debuginfo",
|
split_debuginfo: Option<String> = "split-debuginfo",
|
||||||
llvm_config: Option<String> = "llvm-config",
|
llvm_config: Option<String> = "llvm-config",
|
||||||
@@ -60,6 +64,7 @@ pub struct Target {
|
|||||||
pub ar: Option<PathBuf>,
|
pub ar: Option<PathBuf>,
|
||||||
pub ranlib: Option<PathBuf>,
|
pub ranlib: Option<PathBuf>,
|
||||||
pub default_linker: Option<PathBuf>,
|
pub default_linker: Option<PathBuf>,
|
||||||
|
pub default_linker_linux_override: DefaultLinuxLinkerOverride,
|
||||||
pub linker: Option<PathBuf>,
|
pub linker: Option<PathBuf>,
|
||||||
pub split_debuginfo: Option<SplitDebuginfo>,
|
pub split_debuginfo: Option<SplitDebuginfo>,
|
||||||
pub sanitizers: Option<bool>,
|
pub sanitizers: Option<bool>,
|
||||||
@@ -89,3 +94,60 @@ impl Target {
|
|||||||
target
|
target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Overrides the default linker used on a Linux linker.
|
||||||
|
/// On Linux, the linker is usually invoked through `cc`, therefore this exists as a separate
|
||||||
|
/// configuration from simply setting `default-linker`, which corresponds to `-Clinker`.
|
||||||
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum DefaultLinuxLinkerOverride {
|
||||||
|
/// Do not apply any override and use the default linker for the given target.
|
||||||
|
#[default]
|
||||||
|
Off,
|
||||||
|
/// Use the self-contained `rust-lld` linker, invoked through `cc`.
|
||||||
|
/// Corresponds to `-Clinker-features=+lld -Clink-self-contained=+linker`.
|
||||||
|
SelfContainedLldCc,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for DefaultLinuxLinkerOverride {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let name = String::deserialize(deserializer)?;
|
||||||
|
match name.as_str() {
|
||||||
|
"off" => Ok(Self::Off),
|
||||||
|
"self-contained-lld-cc" => Ok(Self::SelfContainedLldCc),
|
||||||
|
other => Err(D::Error::unknown_variant(other, &["off", "self-contained-lld-cc"])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set of linker overrides for selected Linux targets.
|
||||||
|
#[cfg(not(test))]
|
||||||
|
pub fn default_linux_linker_overrides() -> HashMap<String, DefaultLinuxLinkerOverride> {
|
||||||
|
[("x86_64-unknown-linux-gnu".to_string(), DefaultLinuxLinkerOverride::SelfContainedLldCc)]
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
thread_local! {
|
||||||
|
static TEST_LINUX_LINKER_OVERRIDES: std::cell::RefCell<Option<HashMap<String, DefaultLinuxLinkerOverride>>> = std::cell::RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn default_linux_linker_overrides() -> HashMap<String, DefaultLinuxLinkerOverride> {
|
||||||
|
TEST_LINUX_LINKER_OVERRIDES.with(|cell| cell.borrow().clone()).unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn with_default_linux_linker_overrides<R>(
|
||||||
|
targets: HashMap<String, DefaultLinuxLinkerOverride>,
|
||||||
|
f: impl FnOnce() -> R,
|
||||||
|
) -> R {
|
||||||
|
TEST_LINUX_LINKER_OVERRIDES.with(|cell| {
|
||||||
|
let prev = cell.replace(Some(targets));
|
||||||
|
let result = f();
|
||||||
|
cell.replace(prev);
|
||||||
|
result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user