Skip to content

Commit

Permalink
Move versioned LLVM target creation to rustc_codegen_ssa
Browse files Browse the repository at this point in the history
The OS version depends on the deployment target environment variables,
the access of which we want to move to later in the compilation pipeline
that has access to more information, for example `env_depinfo`.
  • Loading branch information
madsmtm committed Oct 3, 2024
1 parent f7c8928 commit 3a2f4db
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 94 deletions.
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use std::sync::Arc;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::settings::{self, Configurable};
use rustc_codegen_ssa::CodegenResults;
use rustc_codegen_ssa::apple::versioned_llvm_target;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_errors::ErrorGuaranteed;
Expand Down Expand Up @@ -259,7 +260,9 @@ impl CodegenBackend for CraneliftCodegenBackend {
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
match sess.target.llvm_target.parse() {
// FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS.
// See <https://github.com/bytecodealliance/target-lexicon/pull/113>
match versioned_llvm_target(sess).parse() {
Ok(triple) => triple,
Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)),
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use libc::{c_char, c_int, c_void, size_t};
use llvm::{
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
};
use rustc_codegen_ssa::apple::versioned_llvm_target;
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::write::{
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
Expand Down Expand Up @@ -210,7 +211,7 @@ pub(crate) fn target_machine_factory(
singlethread = false;
}

let triple = SmallCStr::new(&sess.target.llvm_target);
let triple = SmallCStr::new(&versioned_llvm_target(sess));
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
let features = CString::new(target_features.join(",")).unwrap();
let abi = SmallCStr::new(&sess.target.llvm_abiname);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::cell::{Cell, RefCell};
use std::ffi::{CStr, c_uint};
use std::str;

use rustc_codegen_ssa::apple::versioned_llvm_target;
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::*;
Expand Down Expand Up @@ -165,7 +166,7 @@ pub(crate) unsafe fn create_module<'ll>(
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
}

let llvm_target = SmallCStr::new(&sess.target.llvm_target);
let llvm_target = SmallCStr::new(&versioned_llvm_target(sess));
unsafe {
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
}
Expand Down
69 changes: 69 additions & 0 deletions compiler/rustc_codegen_ssa/src/apple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::borrow::Cow;
use std::env;

use rustc_session::Session;
use rustc_target::spec::{
AppleOSVersion, apple_deployment_target_env_var, apple_minimum_deployment_target,
apple_parse_version,
};

#[cfg(test)]
mod tests;

/// Get the deployment target based on the standard environment variables, or fall back to the
/// minimum version supported by `rustc`.
pub fn deployment_target(sess: &Session) -> AppleOSVersion {
let min = apple_minimum_deployment_target(&sess.target);

if let Ok(deployment_target) = env::var(apple_deployment_target_env_var(&sess.target.os)) {
match apple_parse_version(&deployment_target) {
// It is common that the deployment target is set too low, e.g. on macOS Aarch64 to also
// target older x86_64, the user may set a lower deployment target than supported.
//
// To avoid such issues, we silently raise the deployment target here.
// FIXME: We want to show a warning when `version < os_min`.
Ok(version) => version.max(min),
// FIXME: Report erroneous environment variable to user.
Err(_) => min,
}
} else {
// If no deployment target variable is set, default to the minimum found above.
min
}
}

fn add_version_to_llvm_target(llvm_target: &str, deployment_target: AppleOSVersion) -> String {
let mut components = llvm_target.split("-");
let arch = components.next().expect("darwin target should have arch");
let vendor = components.next().expect("darwin target should have vendor");
let os = components.next().expect("darwin target should have os");
let environment = components.next();
assert_eq!(components.next(), None, "too many LLVM triple components");

let (major, minor, patch) = deployment_target;

assert!(
!os.contains(|c: char| c.is_ascii_digit()),
"LLVM target must not already be versioned"
);

if let Some(env) = environment {
// Insert version into OS, before environment
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}-{env}")
} else {
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}")
}
}

/// The target triple depends on the deployment target, and is required to
/// enable features such as cross-language LTO, and for picking the right
/// Mach-O commands.
///
/// Certain optimizations also depend on the deployment target.
pub fn versioned_llvm_target(sess: &Session) -> Cow<'static, str> {
if sess.target.is_like_osx {
add_version_to_llvm_target(&sess.target.llvm_target, deployment_target(sess)).into()
} else {
sess.target.llvm_target.clone()
}
}
13 changes: 13 additions & 0 deletions compiler/rustc_codegen_ssa/src/apple/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use super::add_version_to_llvm_target;

#[test]
fn test_add_version_to_llvm_target() {
assert_eq!(
add_version_to_llvm_target("aarch64-apple-macosx", (10, 14, 1)),
"aarch64-apple-macosx10.14.1"
);
assert_eq!(
add_version_to_llvm_target("aarch64-apple-ios-simulator", (16, 1, 0)),
"aarch64-apple-ios16.1.0-simulator"
);
}
13 changes: 7 additions & 6 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use rustc_target::spec::crt_objects::CrtObjects;
use rustc_target::spec::{
Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
SplitDebuginfo, current_apple_deployment_target,
SplitDebuginfo,
};
use tempfile::Builder as TempFileBuilder;
use tracing::{debug, info, warn};
Expand All @@ -50,6 +50,7 @@ use super::command::Command;
use super::linker::{self, Linker};
use super::metadata::{MetadataPosition, create_wrapper_file};
use super::rpath::{self, RPathConfig};
use crate::apple::{deployment_target, versioned_llvm_target};
use crate::{
CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors,
looks_like_rust_object_file,
Expand Down Expand Up @@ -2445,7 +2446,7 @@ fn add_order_independent_options(
if flavor == LinkerFlavor::Llbc {
cmd.link_args(&[
"--target",
sess.target.llvm_target.as_ref(),
&versioned_llvm_target(sess),
"--target-cpu",
&codegen_results.crate_info.target_cpu,
]);
Expand Down Expand Up @@ -3037,7 +3038,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
_ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
};

let (major, minor, patch) = current_apple_deployment_target(&sess.target);
let (major, minor, patch) = deployment_target(sess);
let min_version = format!("{major}.{minor}.{patch}");

// The SDK version is used at runtime when compiling with a newer SDK / version of Xcode:
Expand Down Expand Up @@ -3107,7 +3108,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo

// The presence of `-mmacosx-version-min` makes CC default to
// macOS, and it sets the deployment target.
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
let (major, minor, patch) = deployment_target(sess);
// Intentionally pass this as a single argument, Clang doesn't
// seem to like it otherwise.
cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}"));
Expand All @@ -3117,7 +3118,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
//
// We avoid `-m32`/`-m64`, as this is already encoded by `-arch`.
} else {
cmd.cc_args(&["-target", &sess.target.llvm_target]);
cmd.cc_args(&["-target", &versioned_llvm_target(sess)]);
}
}
}
Expand Down Expand Up @@ -3343,7 +3344,7 @@ fn add_lld_args(
// targeting a different linker flavor on macOS, and that's also always
// the case when targeting WASM.
if sess.target.linker_flavor != sess.host.linker_flavor {
cmd.cc_arg(format!("--target={}", sess.target.llvm_target));
cmd.cc_arg(format!("--target={}", versioned_llvm_target(sess)));
}
}
}
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
}

file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
file.set_macho_build_version(macho_object_build_version_for_target(sess))
}
if binary_format == BinaryFormat::Coff {
// Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
Expand Down Expand Up @@ -391,7 +391,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
///
/// Since Xcode 15, Apple's LD apparently requires object files to use this load command, so this
/// returns the `MachOBuildVersion` for the target to do so.
fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion {
fn macho_object_build_version_for_target(sess: &Session) -> object::write::MachOBuildVersion {
/// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
/// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
fn pack_version((major, minor, patch): (u16, u8, u8)) -> u32 {
Expand All @@ -400,8 +400,8 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach
}

let platform =
rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS");
let min_os = rustc_target::spec::current_apple_deployment_target(target);
rustc_target::spec::current_apple_platform(&sess.target).expect("unknown Apple target OS");
let min_os = crate::apple::deployment_target(sess);

let mut build_version = object::write::MachOBuildVersion::default();
build_version.platform = platform;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ use rustc_session::cstore::{self, CrateSource};
use rustc_session::utils::NativeLibKind;
use rustc_span::symbol::Symbol;

pub mod apple;
pub mod assert_module_sources;
pub mod back;
pub mod base;
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,10 +856,8 @@ fn print_crate_info(
}
}
DeploymentTarget => {
use rustc_target::spec::current_apple_deployment_target;

if sess.target.is_like_osx {
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
let (major, minor, patch) = rustc_codegen_ssa::apple::deployment_target(sess);
let patch = if patch != 0 { format!(".{patch}") } else { String::new() };
println_info!("deployment_target={major}.{minor}{patch}")
} else {
Expand Down
Loading

0 comments on commit 3a2f4db

Please sign in to comment.