Skip to content

Commit 03a896b

Browse files
committed
Revert to always passing --target to Clang
1 parent 353566c commit 03a896b

File tree

4 files changed

+80
-39
lines changed

4 files changed

+80
-39
lines changed

src/lib.rs

+38-23
Original file line numberDiff line numberDiff line change
@@ -2194,21 +2194,34 @@ impl Build {
21942194

21952195
// Pass `--target` with the LLVM target to configure Clang for cross-compiling.
21962196
//
2197-
// NOTE: In the past, we passed this, along with the deployment version in here
2198-
// on Apple targets, but versioned targets were found to have poor compatibility
2199-
// with older versions of Clang, especially around comes to configuration files.
2197+
// This is **required** for cross-compilation, as it's the only flag that
2198+
// consistently forces Clang to change the "toolchain" that is responsible for
2199+
// parsing target-specific flags:
2200+
// https://github.com/rust-lang/cc-rs/issues/1388
2201+
// https://github.com/llvm/llvm-project/blob/llvmorg-19.1.7/clang/lib/Driver/Driver.cpp#L1359-L1360
2202+
// https://github.com/llvm/llvm-project/blob/llvmorg-19.1.7/clang/lib/Driver/Driver.cpp#L6347-L6532
22002203
//
2201-
// Instead, we specify `-arch` along with `-mmacosx-version-min=`, `-mtargetos=`
2202-
// and similar flags in `.apple_flags()`.
2204+
// This can be confusing, because on e.g. host macOS, you can usually get by
2205+
// with `-arch` and `-mtargetos=`. But that only works because the _default_
2206+
// toolchain is `Darwin`, which enables parsing of darwin-specific options.
22032207
//
2204-
// Note that Clang errors when both `-mtargetos=` and `-target` are specified,
2205-
// so we omit this entirely on Apple targets (it's redundant when specifying
2206-
// both the `-arch` and the deployment target / OS flag) (in theory we _could_
2207-
// specify this on some of the Apple targets that use the older
2208-
// `-m*-version-min=`, but for consistency we omit it entirely).
2209-
if target.vendor != "apple" {
2210-
cmd.push_cc_arg(format!("--target={}", target.llvm_target).into());
2211-
}
2208+
// NOTE: In the past, we passed the deployment version in here on all Apple
2209+
// targets, but versioned targets were found to have poor compatibility with
2210+
// older versions of Clang, especially when it comes to configuration files:
2211+
// https://github.com/rust-lang/cc-rs/issues/1278
2212+
//
2213+
// So instead, we pass the deployment target with `-m*-version-min=`, and only
2214+
// pass it here on visionOS and Mac Catalyst where that option does not exist:
2215+
// https://github.com/rust-lang/cc-rs/issues/1383
2216+
let clang_target = if target.os == "visionos" || target.abi == "macabi" {
2217+
Cow::Owned(
2218+
target.versioned_llvm_target(&self.apple_deployment_target(target)),
2219+
)
2220+
} else {
2221+
Cow::Borrowed(target.llvm_target)
2222+
};
2223+
2224+
cmd.push_cc_arg(format!("--target={clang_target}").into());
22122225
}
22132226
}
22142227
ToolFamily::Msvc { clang_cl } => {
@@ -2648,21 +2661,23 @@ impl Build {
26482661
fn apple_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
26492662
let target = self.get_target()?;
26502663

2651-
// Add `-arch` on all compilers. This is a Darwin/Apple-specific flag
2652-
// that works both on GCC and Clang.
2664+
// This is a Darwin/Apple-specific flag that works both on GCC and Clang, but it is only
2665+
// necessary on GCC since we specify `-target` on Clang.
26532666
// https://gcc.gnu.org/onlinedocs/gcc/Darwin-Options.html#:~:text=arch
26542667
// https://clang.llvm.org/docs/CommandGuide/clang.html#cmdoption-arch
2655-
let arch = map_darwin_target_from_rust_to_compiler_architecture(&target);
2656-
cmd.args.push("-arch".into());
2657-
cmd.args.push(arch.into());
2668+
if cmd.is_like_gnu() {
2669+
let arch = map_darwin_target_from_rust_to_compiler_architecture(&target);
2670+
cmd.args.push("-arch".into());
2671+
cmd.args.push(arch.into());
2672+
}
26582673

2659-
// Pass the deployment target via `-mmacosx-version-min=`, `-mtargetos=` and similar.
2660-
//
2661-
// It is also necessary on GCC, as it forces a compilation error if the compiler is not
2674+
// Pass the deployment target via `-mmacosx-version-min=`, `-miphoneos-version-min=` and
2675+
// similar. Also necessary on GCC, as it forces a compilation error if the compiler is not
26622676
// configured for Darwin: https://gcc.gnu.org/onlinedocs/gcc/Darwin-Options.html
26632677
let min_version = self.apple_deployment_target(&target);
2664-
cmd.args
2665-
.push(target.apple_version_flag(&min_version).into());
2678+
if let Some(flag) = target.apple_version_flag(&min_version) {
2679+
cmd.args.push(flag.into());
2680+
}
26662681

26672682
// AppleClang sometimes requires sysroot even on macOS
26682683
if cmd.is_xctoolchain_clang() || target.os != "macos" {

src/target/apple.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl TargetInfo<'_> {
1717
}
1818
}
1919

20-
pub(crate) fn apple_version_flag(&self, min_version: &str) -> String {
20+
pub(crate) fn apple_version_flag(&self, min_version: &str) -> Option<String> {
2121
// There are many aliases for these, and `-mtargetos=` is preferred on Clang nowadays, but
2222
// for compatibility with older Clang, we use the earliest supported name here.
2323
//
@@ -30,20 +30,24 @@ impl TargetInfo<'_> {
3030
// https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mmacos-version-min
3131
// https://clang.llvm.org/docs/AttributeReference.html#availability
3232
// https://gcc.gnu.org/onlinedocs/gcc/Darwin-Options.html#index-mmacosx-version-min
33-
match (self.os, self.abi) {
33+
//
34+
// On visionOS and Mac Catalyst, there is no -m*-version-min= flag:
35+
// https://github.com/llvm/llvm-project/issues/88271
36+
//
37+
// And the workaround to use `-mtargetos=` cannot be used with the `--target` flag that we
38+
// otherwise specify. So we avoid emitting that, and put the version in `--target` instead.
39+
Some(match (self.os, self.abi) {
3440
("macos", "") => format!("-mmacosx-version-min={min_version}"),
3541
("ios", "") => format!("-miphoneos-version-min={min_version}"),
3642
("ios", "sim") => format!("-mios-simulator-version-min={min_version}"),
37-
("ios", "macabi") => format!("-mtargetos=ios{min_version}-macabi"),
43+
("ios", "macabi") => return None, // format!("-mtargetos=ios{min_version}-macabi")
3844
("tvos", "") => format!("-mappletvos-version-min={min_version}"),
3945
("tvos", "sim") => format!("-mappletvsimulator-version-min={min_version}"),
4046
("watchos", "") => format!("-mwatchos-version-min={min_version}"),
4147
("watchos", "sim") => format!("-mwatchsimulator-version-min={min_version}"),
42-
// `-mxros-version-min` does not exist
43-
// https://github.com/llvm/llvm-project/issues/88271
44-
("visionos", "") => format!("-mtargetos=xros{min_version}"),
45-
("visionos", "sim") => format!("-mtargetos=xros{min_version}-simulator"),
48+
("visionos", "") => return None, // format!("-mtargetos=xros{min_version}"),
49+
("visionos", "sim") => return None, // format!("-mtargetos=xros{min_version}-simulator"),
4650
(os, _) => panic!("invalid Apple target OS {}", os),
47-
}
51+
})
4852
}
4953
}

src/target/llvm.rs

+23
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
use super::TargetInfo;
2+
3+
impl TargetInfo<'_> {
4+
/// The versioned LLVM/Clang target triple.
5+
pub(crate) fn versioned_llvm_target(&self, version: &str) -> String {
6+
// Only support versioned Apple targets for now.
7+
assert_eq!(self.vendor, "apple");
8+
9+
let mut components = self.llvm_target.split("-");
10+
let arch = components.next().expect("llvm_target should have arch");
11+
let vendor = components.next().expect("llvm_target should have vendor");
12+
let os = components.next().expect("LLVM target should have os");
13+
let environment = components.next();
14+
assert_eq!(components.next(), None, "too many LLVM target components");
15+
16+
if let Some(env) = environment {
17+
format!("{arch}-{vendor}-{os}{version}-{env}")
18+
} else {
19+
format!("{arch}-{vendor}-{os}{version}")
20+
}
21+
}
22+
}
23+
124
/// Rust and Clang don't really agree on naming, so do a best-effort
225
/// conversion to support out-of-tree / custom target-spec targets.
326
pub(crate) fn guess_llvm_target_triple(

tests/test.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ fn clang_apple_tvos() {
616616
.file("foo.c")
617617
.compile("foo");
618618

619-
test.cmd(0).must_have_in_order("-arch", "arm64");
619+
test.cmd(0).must_have("--target=arm64-apple-tvos");
620620
test.cmd(0).must_have("-mappletvos-version-min=9.0");
621621
}
622622

@@ -640,10 +640,9 @@ fn clang_apple_mac_catalyst() {
640640
.compile("foo");
641641
let execution = test.cmd(0);
642642

643-
execution.must_have_in_order("-arch", "arm64");
643+
execution.must_have("--target=arm64-apple-ios15.0-macabi");
644644
// --target and -mtargetos= don't mix
645-
execution.must_not_have("--target=arm64-apple-ios-macabi");
646-
execution.must_have("-mtargetos=ios15.0-macabi");
645+
execution.must_not_have("-mtargetos=");
647646
execution.must_have_in_order("-isysroot", sdkroot);
648647
execution.must_have_in_order(
649648
"-isystem",
@@ -672,7 +671,8 @@ fn clang_apple_tvsimulator() {
672671
.file("foo.c")
673672
.compile("foo");
674673

675-
test.cmd(0).must_have_in_order("-arch", "x86_64");
674+
test.cmd(0)
675+
.must_have("--target=x86_64-apple-tvos-simulator");
676676
test.cmd(0).must_have("-mappletvsimulator-version-min=9.0");
677677
}
678678

@@ -697,10 +697,9 @@ fn clang_apple_visionos() {
697697

698698
dbg!(test.cmd(0).args);
699699

700-
test.cmd(0).must_have_in_order("-arch", "arm64");
700+
test.cmd(0).must_have("--target=arm64-apple-xros1.0");
701701
// --target and -mtargetos= don't mix.
702-
test.cmd(0).must_not_have("--target=arm64-apple-xros");
703-
test.cmd(0).must_have("-mtargetos=xros1.0");
702+
test.cmd(0).must_not_have("-mtargetos=");
704703

705704
// Flags that don't exist.
706705
test.cmd(0).must_not_have("-mxros-version-min=1.0");

0 commit comments

Comments
 (0)