Skip to content

Commit c70b075

Browse files
committed
Merge branch 'move-llvm-target-versioning' into sdkroot
2 parents f91a3b8 + 7750660 commit c70b075

File tree

13 files changed

+196
-98
lines changed

13 files changed

+196
-98
lines changed

compiler/rustc_codegen_cranelift/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use std::sync::Arc;
3939
use cranelift_codegen::isa::TargetIsa;
4040
use cranelift_codegen::settings::{self, Configurable};
4141
use rustc_codegen_ssa::CodegenResults;
42+
use rustc_codegen_ssa::apple::versioned_llvm_target;
4243
use rustc_codegen_ssa::traits::CodegenBackend;
4344
use rustc_data_structures::profiling::SelfProfilerRef;
4445
use rustc_errors::ErrorGuaranteed;
@@ -259,7 +260,9 @@ impl CodegenBackend for CraneliftCodegenBackend {
259260
}
260261

261262
fn target_triple(sess: &Session) -> target_lexicon::Triple {
262-
match sess.target.llvm_target.parse() {
263+
// FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS.
264+
// See <https://github.com/bytecodealliance/target-lexicon/pull/113>
265+
match versioned_llvm_target(sess).parse() {
263266
Ok(triple) => triple,
264267
Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)),
265268
}

compiler/rustc_codegen_llvm/src/back/write.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use libc::{c_char, c_int, c_void, size_t};
88
use llvm::{
99
LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
1010
};
11+
use rustc_codegen_ssa::apple::versioned_llvm_target;
1112
use rustc_codegen_ssa::back::link::ensure_removed;
1213
use rustc_codegen_ssa::back::write::{
1314
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
@@ -210,7 +211,7 @@ pub(crate) fn target_machine_factory(
210211
singlethread = false;
211212
}
212213

213-
let triple = SmallCStr::new(&sess.target.llvm_target);
214+
let triple = SmallCStr::new(&versioned_llvm_target(sess));
214215
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
215216
let features = CString::new(target_features.join(",")).unwrap();
216217
let abi = SmallCStr::new(&sess.target.llvm_abiname);

compiler/rustc_codegen_llvm/src/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::cell::{Cell, RefCell};
33
use std::ffi::{CStr, c_uint};
44
use std::str;
55

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

168-
let llvm_target = SmallCStr::new(&sess.target.llvm_target);
169+
let llvm_target = SmallCStr::new(&versioned_llvm_target(sess));
169170
unsafe {
170171
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
171172
}

compiler/rustc_codegen_ssa/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not imp
22
33
codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
44
5+
codegen_ssa_apple_deployment_target_invalid =
6+
failed to parse deployment target specified in {$env_var}: {$error}
7+
8+
codegen_ssa_apple_deployment_target_too_low =
9+
deployment target in {$env_var} was set to {$version}, but the minimum supported by `rustc` is {$os_min}
10+
511
codegen_ssa_apple_sdk_error_failed_reading =
612
failed reading `{$path}` while looking for SDK root: {$error}
713

compiler/rustc_codegen_ssa/src/apple.rs

+93-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,104 @@
1+
use std::borrow::Cow;
2+
use std::env;
13
use std::fs;
24
use std::io::ErrorKind;
5+
use std::fmt::{Display, from_fn};
36
use std::path::{Path, PathBuf};
47

5-
use crate::errors::AppleSdkError;
8+
use rustc_session::Session;
9+
use rustc_target::spec::{
10+
AppleOSVersion, apple_deployment_target_env_var, apple_minimum_deployment_target,
11+
apple_os_minimum_deployment_target, apple_parse_version,
12+
};
13+
14+
use crate::errors::{AppleDeploymentTarget, AppleSdkError};
615

716
#[cfg(test)]
817
mod tests;
918

19+
pub fn pretty_version(version: AppleOSVersion) -> impl Display {
20+
let (major, minor, patch) = version;
21+
from_fn(move |f| {
22+
write!(f, "{major}.{minor}")?;
23+
if patch != 0 {
24+
write!(f, ".{patch}")?;
25+
}
26+
Ok(())
27+
})
28+
}
29+
30+
/// Get the deployment target based on the standard environment variables, or fall back to the
31+
/// minimum version supported by `rustc`.
32+
pub fn deployment_target(sess: &Session) -> AppleOSVersion {
33+
let os_min = apple_os_minimum_deployment_target(&sess.target.os);
34+
let min = apple_minimum_deployment_target(&sess.target);
35+
let env_var = apple_deployment_target_env_var(&sess.target.os);
36+
37+
if let Ok(deployment_target) = env::var(env_var) {
38+
match apple_parse_version(&deployment_target) {
39+
Ok(version) => {
40+
// It is common that the deployment target is set a bit too low, for example on
41+
// macOS Aarch64 to also target older x86_64. So we only want to warn when variable
42+
// is lower than the minimum OS supported by rustc, not when the variable is lower
43+
// than the minimum for a specific target.
44+
if version < os_min {
45+
sess.dcx().emit_warn(AppleDeploymentTarget::TooLow {
46+
env_var,
47+
version: pretty_version(version).to_string(),
48+
os_min: pretty_version(os_min).to_string(),
49+
});
50+
}
51+
52+
// Raise the deployment target to the minimum supported.
53+
version.max(min)
54+
}
55+
Err(error) => {
56+
sess.dcx().emit_err(AppleDeploymentTarget::Invalid { env_var, error });
57+
min
58+
}
59+
}
60+
} else {
61+
// If no deployment target variable is set, default to the minimum found above.
62+
min
63+
}
64+
}
65+
66+
fn add_version_to_llvm_target(llvm_target: &str, deployment_target: AppleOSVersion) -> String {
67+
let mut components = llvm_target.split("-");
68+
let arch = components.next().expect("darwin target should have arch");
69+
let vendor = components.next().expect("darwin target should have vendor");
70+
let os = components.next().expect("darwin target should have os");
71+
let environment = components.next();
72+
assert_eq!(components.next(), None, "too many LLVM triple components");
73+
74+
let (major, minor, patch) = deployment_target;
75+
76+
assert!(
77+
!os.contains(|c: char| c.is_ascii_digit()),
78+
"LLVM target must not already be versioned"
79+
);
80+
81+
if let Some(env) = environment {
82+
// Insert version into OS, before environment
83+
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}-{env}")
84+
} else {
85+
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}")
86+
}
87+
}
88+
89+
/// The target triple depends on the deployment target, and is required to
90+
/// enable features such as cross-language LTO, and for picking the right
91+
/// Mach-O commands.
92+
///
93+
/// Certain optimizations also depend on the deployment target.
94+
pub fn versioned_llvm_target(sess: &Session) -> Cow<'static, str> {
95+
if sess.target.is_like_osx {
96+
add_version_to_llvm_target(&sess.target.llvm_target, deployment_target(sess)).into()
97+
} else {
98+
sess.target.llvm_target.clone()
99+
}
100+
}
101+
10102
// TOCTOU is not _really_ an issue with our use of `try_exists` in here, we mostly use it for
11103
// diagnostics, and these directories are global state that the user may change anytime anyhow.
12104
fn try_exists(path: &Path) -> Result<bool, AppleSdkError> {

compiler/rustc_codegen_ssa/src/apple/tests.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@ use std::io;
22
use std::path::PathBuf;
33
use std::process::Command;
44

5-
use super::find_sdk_root;
5+
use super::{add_version_to_llvm_target, find_sdk_root};
6+
7+
#[test]
8+
fn test_add_version_to_llvm_target() {
9+
assert_eq!(
10+
add_version_to_llvm_target("aarch64-apple-macosx", (10, 14, 1)),
11+
"aarch64-apple-macosx10.14.1"
12+
);
13+
assert_eq!(
14+
add_version_to_llvm_target("aarch64-apple-ios-simulator", (16, 1, 0)),
15+
"aarch64-apple-ios16.1.0-simulator"
16+
);
17+
}
618

719
fn find_sdk_root_xcrun(sdk_name: &str) -> io::Result<PathBuf> {
820
let output = Command::new("xcrun")

compiler/rustc_codegen_ssa/src/back/link.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use rustc_target::spec::crt_objects::CrtObjects;
4040
use rustc_target::spec::{
4141
Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
4242
LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
43-
SplitDebuginfo, current_apple_deployment_target,
43+
SplitDebuginfo,
4444
};
4545
use tempfile::Builder as TempFileBuilder;
4646
use tracing::{debug, info, warn};
@@ -50,7 +50,7 @@ use super::command::Command;
5050
use super::linker::{self, Linker};
5151
use super::metadata::{MetadataPosition, create_wrapper_file};
5252
use super::rpath::{self, RPathConfig};
53-
use crate::apple::find_sdk_root;
53+
use crate::apple::{deployment_target, find_sdk_root, versioned_llvm_target};
5454
use crate::{
5555
CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors,
5656
looks_like_rust_object_file,
@@ -2446,7 +2446,7 @@ fn add_order_independent_options(
24462446
if flavor == LinkerFlavor::Llbc {
24472447
cmd.link_args(&[
24482448
"--target",
2449-
sess.target.llvm_target.as_ref(),
2449+
&versioned_llvm_target(sess),
24502450
"--target-cpu",
24512451
&codegen_results.crate_info.target_cpu,
24522452
]);
@@ -3038,7 +3038,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
30383038
_ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
30393039
};
30403040

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

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

31093109
// The presence of `-mmacosx-version-min` makes CC default to
31103110
// macOS, and it sets the deployment target.
3111-
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
3111+
let (major, minor, patch) = deployment_target(sess);
31123112
// Intentionally pass this as a single argument, Clang doesn't
31133113
// seem to like it otherwise.
31143114
cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}"));
@@ -3118,7 +3118,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
31183118
//
31193119
// We avoid `-m32`/`-m64`, as this is already encoded by `-arch`.
31203120
} else {
3121-
cmd.cc_args(&["-target", &sess.target.llvm_target]);
3121+
cmd.cc_args(&["-target", &versioned_llvm_target(sess)]);
31223122
}
31233123
}
31243124
}
@@ -3305,7 +3305,7 @@ fn add_lld_args(
33053305
// targeting a different linker flavor on macOS, and that's also always
33063306
// the case when targeting WASM.
33073307
if sess.target.linker_flavor != sess.host.linker_flavor {
3308-
cmd.cc_arg(format!("--target={}", sess.target.llvm_target));
3308+
cmd.cc_arg(format!("--target={}", versioned_llvm_target(sess)));
33093309
}
33103310
}
33113311
}

compiler/rustc_codegen_ssa/src/back/metadata.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
238238
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
239239
}
240240

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

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

406406
let mut build_version = object::write::MachOBuildVersion::default();
407407
build_version.platform = platform;

compiler/rustc_codegen_ssa/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::borrow::Cow;
44
use std::io::Error;
5+
use std::num::ParseIntError;
56
use std::path::{Path, PathBuf};
67
use std::process::ExitStatus;
78

@@ -532,6 +533,14 @@ pub enum ExtractBundledLibsError<'a> {
532533
ExtractSection { rlib: &'a Path, error: Box<dyn std::error::Error> },
533534
}
534535

536+
#[derive(Diagnostic)]
537+
pub(crate) enum AppleDeploymentTarget {
538+
#[diag(codegen_ssa_apple_deployment_target_invalid)]
539+
Invalid { env_var: &'static str, error: ParseIntError },
540+
#[diag(codegen_ssa_apple_deployment_target_too_low)]
541+
TooLow { env_var: &'static str, version: String, os_min: String },
542+
}
543+
535544
#[derive(Diagnostic, Debug)]
536545
pub(crate) enum AppleSdkError {
537546
#[diag(codegen_ssa_apple_sdk_error_failed_reading)]

compiler/rustc_codegen_ssa/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![doc(rust_logo)]
77
#![feature(assert_matches)]
88
#![feature(box_patterns)]
9+
#![feature(debug_closure_helpers)]
910
#![feature(file_buffered)]
1011
#![feature(if_let_guard)]
1112
#![feature(let_chains)]

compiler/rustc_driver_impl/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -855,12 +855,10 @@ fn print_crate_info(
855855
}
856856
}
857857
DeploymentTarget => {
858-
use rustc_target::spec::current_apple_deployment_target;
858+
use rustc_codegen_ssa::apple::{deployment_target, pretty_version};
859859

860860
if sess.target.is_like_osx {
861-
let (major, minor, patch) = current_apple_deployment_target(&sess.target);
862-
let patch = if patch != 0 { format!(".{patch}") } else { String::new() };
863-
println_info!("deployment_target={major}.{minor}{patch}")
861+
println_info!("deployment_target={}", pretty_version(deployment_target(sess)))
864862
} else {
865863
#[allow(rustc::diagnostic_outside_of_impl)]
866864
sess.dcx().fatal("only Apple targets currently support deployment version info")

0 commit comments

Comments
 (0)