Skip to content

Commit

Permalink
Auto merge of #127992 - Urgau:lazy-targets-link_args, r=<try>
Browse files Browse the repository at this point in the history
Lazify `TargetOptions::*link_args` fields

This PR lazify the link args by introducing `MaybeLazy`, a 3-way lazy container (borrowed, owned and lazied state).

Split from #122703
r? `@petrochenkov`
  • Loading branch information
bors committed Jul 19, 2024
2 parents ff4b398 + 990db03 commit f36d603
Show file tree
Hide file tree
Showing 78 changed files with 524 additions and 292 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(fn_traits)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(min_exhaustive_patterns)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(unboxed_closures)]
// tidy-alphabetical-end

use std::path::{Path, PathBuf};
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_target/src/spec/base/apple/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{borrow::Cow, env};

use crate::spec::{add_link_args, add_link_args_iter};
use crate::spec::link_args::LazyLinkArgsState;
use crate::spec::{add_link_args, add_link_args_iter, MaybeLazy};
use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs, LinkerFlavor, Lld};
use crate::spec::{SplitDebuginfo, StackProbeType, StaticCow, Target, TargetOptions};

Expand Down Expand Up @@ -94,7 +95,10 @@ impl TargetAbi {
}
}

fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs {
pub(crate) type ApplePreLinkArgs =
(/*os:*/ &'static str, /*arch:*/ Arch, /*abi:*/ TargetAbi);

pub(crate) fn pre_link_args((os, arch, abi): ApplePreLinkArgs) -> LinkArgs {
let platform_name: StaticCow<str> = match abi {
TargetAbi::Normal => os.into(),
TargetAbi::Simulator => format!("{os}-simulator").into(),
Expand All @@ -114,7 +118,9 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs {
};
let sdk_version = min_version.clone();

let mut args = TargetOptions::link_args(
let mut args = LinkArgs::new();
add_link_args(
&mut args,
LinkerFlavor::Darwin(Cc::No, Lld::No),
&["-arch", arch.target_name(), "-platform_version"],
);
Expand Down Expand Up @@ -151,7 +157,7 @@ pub fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOptions {
// macOS has -dead_strip, which doesn't rely on function_sections
function_sections: false,
dynamic_linking: true,
pre_link_args: pre_link_args(os, arch, abi),
pre_link_args: MaybeLazy::lazied(LazyLinkArgsState::Apple((os, arch, abi))),
families: cvs!["unix"],
is_like_osx: true,
// LLVM notes that macOS 10.11+ and iOS 9+ default
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_target/src/spec/base/avr_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use object::elf;
/// A base target for AVR devices using the GNU toolchain.
///
/// Requires GNU avr-gcc and avr-binutils on the host system.
/// FIXME: Remove the second parameter when const string concatenation is possible.
pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
pub fn target(target_cpu: &'static str) -> Target {
Target {
arch: "avr".into(),
metadata: crate::spec::TargetMetadata {
Expand All @@ -24,7 +23,10 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {

linker: Some("avr-gcc".into()),
eh_frame_header: false,
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]),
pre_link_args: TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-mmcu=atmega328"],
),
late_link_args: TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-lgcc"],
Expand Down
16 changes: 10 additions & 6 deletions compiler/rustc_target/src/spec/base/teeos.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use crate::spec::{add_link_args, Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, TargetOptions};
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, TargetOptions};

pub fn opts() -> TargetOptions {
let lld_args = &["-zmax-page-size=4096", "-znow", "-ztext", "--execute-only"];
let cc_args = &["-Wl,-zmax-page-size=4096", "-Wl,-znow", "-Wl,-ztext", "-mexecute-only"];

let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), lld_args);
add_link_args(&mut pre_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), cc_args);
let pre_link_args = {
const LLD_ARGS: &[&str] = &["-zmax-page-size=4096", "-znow", "-ztext", "--execute-only"];
const CC_ARGS: &[&str] =
&["-Wl,-zmax-page-size=4096", "-Wl,-znow", "-Wl,-ztext", "-mexecute-only"];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), LLD_ARGS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), CC_ARGS),
])
};

TargetOptions {
os: "teeos".into(),
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_target/src/spec/base/uefi_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
// code runs in the same environment, no process separation is supported.

use crate::spec::{base, LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions};
use crate::spec::{base, LinkerFlavor, Lld};
use crate::spec::{PanicStrategy, StackProbeType, TargetOptions};

pub fn opts() -> TargetOptions {
let mut base = base::msvc::opts();

base.add_pre_link_args(
base.pre_link_args = TargetOptions::link_args(
LinkerFlavor::Msvc(Lld::No),
&[
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_target/src/spec/base/wasm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::spec::{
add_link_args, cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel,
TargetOptions, TlsModel,
};
use crate::spec::{cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy};
use crate::spec::{RelocModel, TargetOptions, TlsModel};

pub fn options() -> TargetOptions {
macro_rules! args {
Expand Down Expand Up @@ -48,8 +46,10 @@ pub fn options() -> TargetOptions {
};
}

let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
let pre_link_args = TargetOptions::link_args_list(&[
(LinkerFlavor::WasmLld(Cc::No), args!("")),
(LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,")),
]);

TargetOptions {
is_like_wasm: true,
Expand Down
124 changes: 63 additions & 61 deletions compiler/rustc_target/src/spec/base/windows_gnu.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,80 @@
use crate::spec::crt_objects;
use crate::spec::LinkSelfContainedDefault;
use crate::spec::{add_link_args, crt_objects};
use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;

pub fn opts() -> TargetOptions {
let mut pre_link_args = TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
// Enable ASLR
"--dynamicbase",
// ASLR will rebase it anyway so leaving that option enabled only leads to confusion
"--disable-auto-image-base",
],
);
add_link_args(
&mut pre_link_args,
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&[
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
"-fno-use-linker-plugin",
"-Wl,--dynamicbase",
"-Wl,--disable-auto-image-base",
],
);
let pre_link_args = TargetOptions::link_args_list(&[
(
LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
// Enable ASLR
"--dynamicbase",
// ASLR will rebase it anyway so leaving that option enabled only leads to confusion
"--disable-auto-image-base",
],
),
(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&[
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
"-fno-use-linker-plugin",
"-Wl,--dynamicbase",
"-Wl,--disable-auto-image-base",
],
),
]);

// Order of `late_link_args*` was found through trial and error to work with various
// mingw-w64 versions (not tested on the CI). It's expected to change from time to time.
let mingw_libs = &[
"-lmsvcrt",
"-lmingwex",
"-lmingw32",
"-lgcc", // alas, mingw* libraries above depend on libgcc
// mingw's msvcrt is a weird hybrid import library and static library.
// And it seems that the linker fails to use import symbols from msvcrt
// that are required from functions in msvcrt in certain cases. For example
// `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
// The library is purposely listed twice to fix that.
//
// See https://github.com/rust-lang/rust/pull/47483 for some more details.
"-lmsvcrt",
// Math functions missing in MSVCRT (they are present in UCRT) require
// this dependency cycle: `libmingwex.a` -> `libmsvcrt.a` -> `libmingwex.a`.
"-lmingwex",
"-luser32",
"-lkernel32",
];
let mut late_link_args =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs);
add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs);
let late_link_args = {
// Order of `late_link_args*` was found through trial and error to work with various
// mingw-w64 versions (not tested on the CI). It's expected to change from time to time.
const MINGW_LIBS: &[&str] = &[
"-lmsvcrt",
"-lmingwex",
"-lmingw32",
"-lgcc", // alas, mingw* libraries above depend on libgcc
// mingw's msvcrt is a weird hybrid import library and static library.
// And it seems that the linker fails to use import symbols from msvcrt
// that are required from functions in msvcrt in certain cases. For example
// `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
// The library is purposely listed twice to fix that.
//
// See https://github.com/rust-lang/rust/pull/47483 for some more details.
"-lmsvcrt",
// Math functions missing in MSVCRT (they are present in UCRT) require
// this dependency cycle: `libmingwex.a` -> `libmsvcrt.a` -> `libmingwex.a`.
"-lmingwex",
"-luser32",
"-lkernel32",
];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), MINGW_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), MINGW_LIBS),
])
};
// If any of our crates are dynamically linked then we need to use
// the shared libgcc_s-dw2-1.dll. This is required to support
// unwinding across DLL boundaries.
let dynamic_unwind_libs = &["-lgcc_s"];
let mut late_link_args_dynamic =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), dynamic_unwind_libs);
add_link_args(
&mut late_link_args_dynamic,
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
dynamic_unwind_libs,
);
let late_link_args_dynamic = {
const DYNAMIC_UNWIND_LIBS: &[&str] = &["-lgcc_s"];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), DYNAMIC_UNWIND_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), DYNAMIC_UNWIND_LIBS),
])
};
// If all of our crates are statically linked then we can get away
// with statically linking the libgcc unwinding code. This allows
// binaries to be redistributed without the libgcc_s-dw2-1.dll
// dependency, but unfortunately break unwinding across DLL
// boundaries when unwinding across FFI boundaries.
let static_unwind_libs = &["-lgcc_eh", "-l:libpthread.a"];
let mut late_link_args_static =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), static_unwind_libs);
add_link_args(
&mut late_link_args_static,
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
static_unwind_libs,
);
let late_link_args_static = {
const STATIC_UNWIND_LIBS: &[&str] = &["-lgcc_eh", "-l:libpthread.a"];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), STATIC_UNWIND_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), STATIC_UNWIND_LIBS),
])
};

TargetOptions {
os: "windows".into(),
Expand Down
39 changes: 21 additions & 18 deletions compiler/rustc_target/src/spec/base/windows_uwp_gnu.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
use crate::spec::{add_link_args, base, Cc, LinkArgs, LinkerFlavor, Lld, TargetOptions};
use crate::spec::{base, Cc, LinkerFlavor, Lld, TargetOptions};

pub fn opts() -> TargetOptions {
let base = base::windows_gnu::opts();

// FIXME: This should be updated for the exception machinery changes from #67502
// and inherit from `windows_gnu_base`, at least partially.
let mingw_libs = &[
"-lwinstorecompat",
"-lruntimeobject",
"-lsynchronization",
"-lvcruntime140_app",
"-lucrt",
"-lwindowsapp",
"-lmingwex",
"-lmingw32",
];
let mut late_link_args =
TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs);
add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs);
let late_link_args = {
// FIXME: This should be updated for the exception machinery changes from #67502
// and inherit from `windows_gnu_base`, at least partially.
const MINGW_LIBS: &[&str] = &[
"-lwinstorecompat",
"-lruntimeobject",
"-lsynchronization",
"-lvcruntime140_app",
"-lucrt",
"-lwindowsapp",
"-lmingwex",
"-lmingw32",
];
TargetOptions::link_args_list(&[
(LinkerFlavor::Gnu(Cc::No, Lld::No), MINGW_LIBS),
(LinkerFlavor::Gnu(Cc::Yes, Lld::No), MINGW_LIBS),
])
};
// Reset the flags back to empty until the FIXME above is addressed.
let late_link_args_dynamic = LinkArgs::new();
let late_link_args_static = LinkArgs::new();
let late_link_args_dynamic = Default::default();
let late_link_args_static = Default::default();

TargetOptions {
abi: "uwp".into(),
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ pub fn opts() -> TargetOptions {

opts.abi = "uwp".into();
opts.vendor = "uwp".into();
opts.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]);
opts.pre_link_args =
TargetOptions::link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]);

opts
}
41 changes: 41 additions & 0 deletions compiler/rustc_target/src/spec/link_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! Linker arguments
use crate::spec::add_link_args;
use crate::spec::{LinkerFlavor, LinkerFlavorCli};
use crate::spec::{MaybeLazy, StaticCow};

use std::collections::BTreeMap;

pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>;

pub type LazyLinkArgs = MaybeLazy<LinkArgs, LazyLinkArgsState>;

pub enum LazyLinkArgsState {
Simple(LinkerFlavor, &'static [&'static str]),
List(&'static [(LinkerFlavor, &'static [&'static str])]),
Apple(super::base::apple::ApplePreLinkArgs),
}

impl FnOnce<()> for LazyLinkArgsState {
type Output = LinkArgs;

#[inline]
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
match self {
LazyLinkArgsState::Simple(flavor, args) => {
let mut link_args = LinkArgs::new();
add_link_args(&mut link_args, flavor, args);
link_args
}
LazyLinkArgsState::List(l) => {
let mut link_args = LinkArgs::new();
for (flavor, args) in l {
add_link_args(&mut link_args, *flavor, args)
}
link_args
}
LazyLinkArgsState::Apple(args) => super::base::apple::pre_link_args(args),
}
}
}
Loading

0 comments on commit f36d603

Please sign in to comment.