Introduce LldMode
and generalize parsing of use-lld
This commit is contained in:
parent
d9f9e67bc1
commit
48c1607bc6
5 changed files with 99 additions and 12 deletions
|
@ -870,7 +870,7 @@ impl Step for Rustc {
|
||||||
// is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
|
// is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
|
||||||
// https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
|
// https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
|
||||||
// https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
|
// https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
|
||||||
if builder.config.use_lld && !compiler.host.is_msvc() {
|
if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() {
|
||||||
cargo.rustflag("-Clink-args=-Wl,--icf=all");
|
cargo.rustflag("-Clink-args=-Wl,--icf=all");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,39 @@ impl Display for DebuginfoLevel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// LLD in bootstrap works like this:
|
||||||
|
/// - Self-contained lld: use `rust-lld` from the compiler's sysroot
|
||||||
|
/// - External: use an external `lld` binary
|
||||||
|
///
|
||||||
|
/// It is configured depending on the target:
|
||||||
|
/// 1) Everything except MSVC
|
||||||
|
/// - Self-contained: -Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker
|
||||||
|
/// - External: -Clinker-flavor=gnu-lld-cc
|
||||||
|
/// 2) MSVC
|
||||||
|
/// - Self-contained: -Clinker=<path to rust-lld>
|
||||||
|
/// - External: -Clinker=lld
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub enum LldMode {
|
||||||
|
/// Do not use LLD
|
||||||
|
#[default]
|
||||||
|
Unused,
|
||||||
|
/// Use `rust-lld` from the compiler's sysroot
|
||||||
|
SelfContained,
|
||||||
|
/// Use an externally provided `lld` binary.
|
||||||
|
/// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has
|
||||||
|
/// to be in $PATH.
|
||||||
|
External,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LldMode {
|
||||||
|
pub fn is_used(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
LldMode::SelfContained | LldMode::External => true,
|
||||||
|
LldMode::Unused => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Global configuration for the entire build and/or bootstrap.
|
/// Global configuration for the entire build and/or bootstrap.
|
||||||
///
|
///
|
||||||
/// This structure is parsed from `config.toml`, and some of the fields are inferred from `git` or build-time parameters.
|
/// This structure is parsed from `config.toml`, and some of the fields are inferred from `git` or build-time parameters.
|
||||||
|
@ -199,7 +232,7 @@ pub struct Config {
|
||||||
pub llvm_from_ci: bool,
|
pub llvm_from_ci: bool,
|
||||||
pub llvm_build_config: HashMap<String, String>,
|
pub llvm_build_config: HashMap<String, String>,
|
||||||
|
|
||||||
pub use_lld: bool,
|
pub lld_mode: LldMode,
|
||||||
pub lld_enabled: bool,
|
pub lld_enabled: bool,
|
||||||
pub llvm_tools_enabled: bool,
|
pub llvm_tools_enabled: bool,
|
||||||
|
|
||||||
|
@ -981,6 +1014,44 @@ enum StringOrInt<'a> {
|
||||||
String(&'a str),
|
String(&'a str),
|
||||||
Int(i64),
|
Int(i64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for LldMode {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct LldModeVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for LldModeVisitor {
|
||||||
|
type Value = LldMode;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
formatter.write_str("one of true, 'self-contained' or 'external'")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(if v { LldMode::External } else { LldMode::Unused })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match v {
|
||||||
|
"external" => Ok(LldMode::External),
|
||||||
|
"self-contained" => Ok(LldMode::SelfContained),
|
||||||
|
_ => Err(E::custom("unknown mode {v}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(LldModeVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
/// TOML representation of how the Rust build is configured.
|
/// TOML representation of how the Rust build is configured.
|
||||||
struct Rust {
|
struct Rust {
|
||||||
|
@ -1018,7 +1089,7 @@ define_config! {
|
||||||
save_toolstates: Option<String> = "save-toolstates",
|
save_toolstates: Option<String> = "save-toolstates",
|
||||||
codegen_backends: Option<Vec<String>> = "codegen-backends",
|
codegen_backends: Option<Vec<String>> = "codegen-backends",
|
||||||
lld: Option<bool> = "lld",
|
lld: Option<bool> = "lld",
|
||||||
use_lld: Option<bool> = "use-lld",
|
lld_mode: Option<LldMode> = "use-lld",
|
||||||
llvm_tools: Option<bool> = "llvm-tools",
|
llvm_tools: Option<bool> = "llvm-tools",
|
||||||
deny_warnings: Option<bool> = "deny-warnings",
|
deny_warnings: Option<bool> = "deny-warnings",
|
||||||
backtrace_on_ice: Option<bool> = "backtrace-on-ice",
|
backtrace_on_ice: Option<bool> = "backtrace-on-ice",
|
||||||
|
@ -1446,7 +1517,7 @@ impl Config {
|
||||||
if let Some(true) = rust.incremental {
|
if let Some(true) = rust.incremental {
|
||||||
config.incremental = true;
|
config.incremental = true;
|
||||||
}
|
}
|
||||||
set(&mut config.use_lld, rust.use_lld);
|
set(&mut config.lld_mode, rust.lld_mode);
|
||||||
set(&mut config.lld_enabled, rust.lld);
|
set(&mut config.lld_enabled, rust.lld);
|
||||||
set(&mut config.llvm_tools_enabled, rust.llvm_tools);
|
set(&mut config.llvm_tools_enabled, rust.llvm_tools);
|
||||||
config.rustc_parallel = rust
|
config.rustc_parallel = rust
|
||||||
|
|
|
@ -37,7 +37,7 @@ use utils::channel::GitInfo;
|
||||||
|
|
||||||
use crate::core::builder;
|
use crate::core::builder;
|
||||||
use crate::core::builder::Kind;
|
use crate::core::builder::Kind;
|
||||||
use crate::core::config::flags;
|
use crate::core::config::{flags, LldMode};
|
||||||
use crate::core::config::{DryRun, Target};
|
use crate::core::config::{DryRun, Target};
|
||||||
use crate::core::config::{LlvmLibunwind, TargetSelection};
|
use crate::core::config::{LlvmLibunwind, TargetSelection};
|
||||||
use crate::utils::cache::{Interned, INTERNER};
|
use crate::utils::cache::{Interned, INTERNER};
|
||||||
|
@ -1258,17 +1258,24 @@ impl Build {
|
||||||
&& !target.is_msvc()
|
&& !target.is_msvc()
|
||||||
{
|
{
|
||||||
Some(self.cc(target))
|
Some(self.cc(target))
|
||||||
} else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target {
|
} else if self.config.lld_mode.is_used()
|
||||||
Some(self.initial_lld.clone())
|
&& self.is_lld_direct_linker(target)
|
||||||
|
&& self.build == target
|
||||||
|
{
|
||||||
|
match self.config.lld_mode {
|
||||||
|
LldMode::SelfContained => Some(self.initial_lld.clone()),
|
||||||
|
LldMode::External => Some("lld".into()),
|
||||||
|
LldMode::Unused => None,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLD is used through `-fuse-ld=lld` rather than directly.
|
// Is LLD configured directly through `-Clinker`?
|
||||||
// Only MSVC targets use LLD directly at the moment.
|
// Only MSVC targets use LLD directly at the moment.
|
||||||
fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool {
|
fn is_lld_direct_linker(&self, target: TargetSelection) -> bool {
|
||||||
self.config.use_lld && !target.is_msvc()
|
target.is_msvc()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns if this target should statically link the C runtime, if specified
|
/// Returns if this target should statically link the C runtime, if specified
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::core::config::TomlConfig;
|
|
||||||
use super::{Config, Flags};
|
use super::{Config, Flags};
|
||||||
|
use crate::core::config::{LldMode, TomlConfig};
|
||||||
|
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -217,3 +217,12 @@ fn verify_file_integrity() {
|
||||||
|
|
||||||
remove_file(tempfile).unwrap();
|
remove_file(tempfile).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rust_lld() {
|
||||||
|
assert!(matches!(parse("").lld_mode, LldMode::Unused));
|
||||||
|
assert!(matches!(parse("rust.use-lld = \"self-contained\"").lld_mode, LldMode::SelfContained));
|
||||||
|
assert!(matches!(parse("rust.use-lld = \"external\"").lld_mode, LldMode::External));
|
||||||
|
assert!(matches!(parse("rust.use-lld = true").lld_mode, LldMode::External));
|
||||||
|
assert!(matches!(parse("rust.use-lld = false").lld_mode, LldMode::Unused));
|
||||||
|
}
|
||||||
|
|
|
@ -499,7 +499,7 @@ pub fn linker_flags(
|
||||||
lld_threads: LldThreads,
|
lld_threads: LldThreads,
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
if builder.is_fuse_ld_lld(target) {
|
if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() {
|
||||||
args.push(String::from("-Clink-arg=-fuse-ld=lld"));
|
args.push(String::from("-Clink-arg=-fuse-ld=lld"));
|
||||||
|
|
||||||
if matches!(lld_threads, LldThreads::No) {
|
if matches!(lld_threads, LldThreads::No) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue