Skip to content

Commit

Permalink
Introduce LldMode and generalize parsing of use-lld
Browse files Browse the repository at this point in the history
  • Loading branch information
Kobzol committed Dec 10, 2023
1 parent d9f9e67 commit 48c1607
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ impl Step for Rustc {
// 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/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");
}

Expand Down
77 changes: 74 additions & 3 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
/// This structure is parsed from `config.toml`, and some of the fields are inferred from `git` or build-time parameters.
Expand Down Expand Up @@ -199,7 +232,7 @@ pub struct Config {
pub llvm_from_ci: bool,
pub llvm_build_config: HashMap<String, String>,

pub use_lld: bool,
pub lld_mode: LldMode,
pub lld_enabled: bool,
pub llvm_tools_enabled: bool,

Expand Down Expand Up @@ -981,6 +1014,44 @@ enum StringOrInt<'a> {
String(&'a str),
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! {
/// TOML representation of how the Rust build is configured.
struct Rust {
Expand Down Expand Up @@ -1018,7 +1089,7 @@ define_config! {
save_toolstates: Option<String> = "save-toolstates",
codegen_backends: Option<Vec<String>> = "codegen-backends",
lld: Option<bool> = "lld",
use_lld: Option<bool> = "use-lld",
lld_mode: Option<LldMode> = "use-lld",
llvm_tools: Option<bool> = "llvm-tools",
deny_warnings: Option<bool> = "deny-warnings",
backtrace_on_ice: Option<bool> = "backtrace-on-ice",
Expand Down Expand Up @@ -1446,7 +1517,7 @@ impl Config {
if let Some(true) = rust.incremental {
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.llvm_tools_enabled, rust.llvm_tools);
config.rustc_parallel = rust
Expand Down
19 changes: 13 additions & 6 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use utils::channel::GitInfo;

use crate::core::builder;
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::{LlvmLibunwind, TargetSelection};
use crate::utils::cache::{Interned, INTERNER};
Expand Down Expand Up @@ -1258,17 +1258,24 @@ impl Build {
&& !target.is_msvc()
{
Some(self.cc(target))
} else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target {
Some(self.initial_lld.clone())
} else if self.config.lld_mode.is_used()
&& 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 {
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.
fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool {
self.config.use_lld && !target.is_msvc()
fn is_lld_direct_linker(&self, target: TargetSelection) -> bool {
target.is_msvc()
}

/// Returns if this target should statically link the C runtime, if specified
Expand Down
11 changes: 10 additions & 1 deletion src/bootstrap/src/tests/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::core::config::TomlConfig;
use super::{Config, Flags};
use crate::core::config::{LldMode, TomlConfig};

use clap::CommandFactory;
use serde::Deserialize;
Expand Down Expand Up @@ -217,3 +217,12 @@ fn verify_file_integrity() {

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));
}
2 changes: 1 addition & 1 deletion src/bootstrap/src/utils/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ pub fn linker_flags(
lld_threads: LldThreads,
) -> Vec<String> {
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"));

if matches!(lld_threads, LldThreads::No) {
Expand Down

0 comments on commit 48c1607

Please sign in to comment.