Skip to content

Commit daab924

Browse files
Use rustc's Apple deployment target defaults when available (#848)
* use MACOSX_DEPLOYMENT_TARGET when set * Use rustc's minimum Apple deployment targets when available * Obtain deployment target consistently Fix the now-unified default watchOS deployment target --------- Co-authored-by: Jeong YunWon <[email protected]>
1 parent 0d082a2 commit daab924

File tree

2 files changed

+150
-54
lines changed

2 files changed

+150
-54
lines changed

src/lib.rs

Lines changed: 132 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,8 +1832,8 @@ impl Build {
18321832
if let Some(arch) =
18331833
map_darwin_target_from_rust_to_compiler_architecture(target)
18341834
{
1835-
let deployment_target = env::var("IPHONEOS_DEPLOYMENT_TARGET")
1836-
.unwrap_or_else(|_| "7.0".into());
1835+
let deployment_target =
1836+
self.apple_deployment_version(AppleOs::Ios, target, None);
18371837
cmd.args.push(
18381838
format!(
18391839
"--target={}-apple-ios{}-simulator",
@@ -1846,8 +1846,8 @@ impl Build {
18461846
if let Some(arch) =
18471847
map_darwin_target_from_rust_to_compiler_architecture(target)
18481848
{
1849-
let deployment_target = env::var("WATCHOS_DEPLOYMENT_TARGET")
1850-
.unwrap_or_else(|_| "5.0".into());
1849+
let deployment_target =
1850+
self.apple_deployment_version(AppleOs::WatchOs, target, None);
18511851
cmd.args.push(
18521852
format!(
18531853
"--target={}-apple-watchos{}-simulator",
@@ -2141,8 +2141,8 @@ impl Build {
21412141
}
21422142
}
21432143

2144-
if target.contains("apple-ios") || target.contains("apple-watchos") {
2145-
self.ios_watchos_flags(cmd)?;
2144+
if target.contains("-apple-") {
2145+
self.apple_flags(cmd)?;
21462146
}
21472147

21482148
if self.static_flag.unwrap_or(false) {
@@ -2360,37 +2360,30 @@ impl Build {
23602360
Ok(())
23612361
}
23622362

2363-
fn ios_watchos_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
2363+
fn apple_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
23642364
enum ArchSpec {
23652365
Device(&'static str),
23662366
Simulator(&'static str),
23672367
Catalyst(&'static str),
23682368
}
23692369

2370-
enum Os {
2371-
Ios,
2372-
WatchOs,
2373-
}
2374-
impl Display for Os {
2375-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2376-
match self {
2377-
Os::Ios => f.write_str("iOS"),
2378-
Os::WatchOs => f.write_str("WatchOS"),
2379-
}
2380-
}
2381-
}
2382-
23832370
let target = self.get_target()?;
2384-
let os = if target.contains("-watchos") {
2385-
Os::WatchOs
2371+
let os = if target.contains("-darwin") {
2372+
AppleOs::MacOs
2373+
} else if target.contains("-watchos") {
2374+
AppleOs::WatchOs
23862375
} else {
2387-
Os::Ios
2376+
AppleOs::Ios
2377+
};
2378+
let is_mac = match os {
2379+
AppleOs::MacOs => true,
2380+
_ => false,
23882381
};
23892382

2390-
let arch = target.split('-').nth(0).ok_or_else(|| {
2383+
let arch_str = target.split('-').nth(0).ok_or_else(|| {
23912384
Error::new(
23922385
ErrorKind::ArchitectureInvalid,
2393-
format!("Unknown architecture for {} target.", os),
2386+
format!("Unknown architecture for {:?} target.", os),
23942387
)
23952388
})?;
23962389

@@ -2404,11 +2397,22 @@ impl Build {
24042397
None => false,
24052398
};
24062399

2407-
let arch = if is_catalyst {
2408-
match arch {
2400+
let arch = if is_mac {
2401+
match arch_str {
2402+
"i686" => ArchSpec::Device("-m32"),
2403+
"x86_64" | "x86_64h" | "aarch64" => ArchSpec::Device("-m64"),
2404+
_ => {
2405+
return Err(Error::new(
2406+
ErrorKind::ArchitectureInvalid,
2407+
"Unknown architecture for macOS target.",
2408+
));
2409+
}
2410+
}
2411+
} else if is_catalyst {
2412+
match arch_str {
24092413
"arm64e" => ArchSpec::Catalyst("arm64e"),
24102414
"arm64" | "aarch64" => ArchSpec::Catalyst("arm64"),
2411-
"x86_64" => ArchSpec::Catalyst("-m64"),
2415+
"x86_64" | "x86_64h" => ArchSpec::Catalyst("-m64"),
24122416
_ => {
24132417
return Err(Error::new(
24142418
ErrorKind::ArchitectureInvalid,
@@ -2417,9 +2421,9 @@ impl Build {
24172421
}
24182422
}
24192423
} else if is_sim {
2420-
match arch {
2424+
match arch_str {
24212425
"arm64" | "aarch64" => ArchSpec::Simulator("arm64"),
2422-
"x86_64" => ArchSpec::Simulator("-m64"),
2426+
"x86_64" | "x86_64h" => ArchSpec::Simulator("-m64"),
24232427
_ => {
24242428
return Err(Error::new(
24252429
ErrorKind::ArchitectureInvalid,
@@ -2428,38 +2432,37 @@ impl Build {
24282432
}
24292433
}
24302434
} else {
2431-
match arch {
2435+
match arch_str {
24322436
"arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
24332437
"armv7k" => ArchSpec::Device("armv7k"),
24342438
"armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
24352439
"arm64e" => ArchSpec::Device("arm64e"),
24362440
"arm64" | "aarch64" => ArchSpec::Device("arm64"),
24372441
"arm64_32" => ArchSpec::Device("arm64_32"),
24382442
"i386" | "i686" => ArchSpec::Simulator("-m32"),
2439-
"x86_64" => ArchSpec::Simulator("-m64"),
2443+
"x86_64" | "x86_64h" => ArchSpec::Simulator("-m64"),
24402444
_ => {
24412445
return Err(Error::new(
24422446
ErrorKind::ArchitectureInvalid,
2443-
format!("Unknown architecture for {} target.", os),
2447+
format!("Unknown architecture for {:?} target.", os),
24442448
));
24452449
}
24462450
}
24472451
};
24482452

2449-
let (sdk_prefix, sim_prefix, min_version) = match os {
2450-
Os::Ios => (
2451-
"iphone",
2452-
"ios-",
2453-
std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into()),
2454-
),
2455-
Os::WatchOs => (
2456-
"watch",
2457-
"watch",
2458-
std::env::var("WATCHOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "2.0".into()),
2459-
),
2453+
let min_version = self.apple_deployment_version(os, &target, Some(arch_str));
2454+
let (sdk_prefix, sim_prefix) = match os {
2455+
AppleOs::MacOs => ("macosx", ""),
2456+
AppleOs::Ios => ("iphone", "ios-"),
2457+
AppleOs::WatchOs => ("watch", "watch"),
24602458
};
24612459

24622460
let sdk = match arch {
2461+
ArchSpec::Device(_) if is_mac => {
2462+
cmd.args
2463+
.push(format!("-mmacosx-version-min={}", min_version).into());
2464+
"macosx".to_owned()
2465+
}
24632466
ArchSpec::Device(arch) => {
24642467
cmd.args.push("-arch".into());
24652468
cmd.args.push(arch.into());
@@ -2482,17 +2485,19 @@ impl Build {
24822485
ArchSpec::Catalyst(_) => "macosx".to_owned(),
24832486
};
24842487

2485-
self.print(&format_args!("Detecting {} SDK path for {}", os, sdk));
2486-
let sdk_path = if let Some(sdkroot) = env::var_os("SDKROOT") {
2487-
sdkroot
2488-
} else {
2489-
self.apple_sdk_root(sdk.as_str())?
2490-
};
2488+
if !is_mac {
2489+
self.print(&format_args!("Detecting {:?} SDK path for {}", os, sdk));
2490+
let sdk_path = if let Some(sdkroot) = env::var_os("SDKROOT") {
2491+
sdkroot
2492+
} else {
2493+
self.apple_sdk_root(sdk.as_str())?
2494+
};
24912495

2492-
cmd.args.push("-isysroot".into());
2493-
cmd.args.push(sdk_path);
2494-
// TODO: Remove this once Apple stops accepting apps built with Xcode 13
2495-
cmd.args.push("-fembed-bitcode".into());
2496+
cmd.args.push("-isysroot".into());
2497+
cmd.args.push(sdk_path);
2498+
// TODO: Remove this once Apple stops accepting apps built with Xcode 13
2499+
cmd.args.push("-fembed-bitcode".into());
2500+
}
24962501

24972502
Ok(())
24982503
}
@@ -3399,6 +3404,63 @@ impl Build {
33993404
Ok(ret)
34003405
}
34013406

3407+
fn apple_deployment_version(
3408+
&self,
3409+
os: AppleOs,
3410+
target: &str,
3411+
arch_str: Option<&str>,
3412+
) -> String {
3413+
fn rustc_provided_target(rustc: Option<&str>, target: &str) -> Option<String> {
3414+
let rustc = rustc?;
3415+
let output = Command::new(rustc)
3416+
.args(&["--target", target])
3417+
.args(&["--print", "deployment-target"])
3418+
.output()
3419+
.ok()?;
3420+
3421+
if output.status.success() {
3422+
std::str::from_utf8(&output.stdout)
3423+
.unwrap()
3424+
.strip_prefix("deployment_target=")
3425+
.map(|v| v.trim())
3426+
.map(ToString::to_string)
3427+
} else {
3428+
// rustc is < 1.71
3429+
None
3430+
}
3431+
}
3432+
3433+
let rustc = self.getenv("RUSTC");
3434+
let rustc = rustc.as_deref();
3435+
// note the hardcoded minimums here are subject to change in a future compiler release,
3436+
// so the ones rustc knows about are preferred. For any compiler version that has bumped them
3437+
// though, `--print deployment-target` will be present and the fallbacks won't be used.
3438+
//
3439+
// the ordering of env -> rustc -> old defaults is intentional for performance when using
3440+
// an explicit target
3441+
match os {
3442+
AppleOs::MacOs => env::var("MACOSX_DEPLOYMENT_TARGET")
3443+
.ok()
3444+
.or_else(|| rustc_provided_target(rustc, target))
3445+
.unwrap_or_else(|| {
3446+
if arch_str == Some("aarch64") {
3447+
"11.0"
3448+
} else {
3449+
"10.7"
3450+
}
3451+
.into()
3452+
}),
3453+
AppleOs::Ios => env::var("IPHONEOS_DEPLOYMENT_TARGET")
3454+
.ok()
3455+
.or_else(|| rustc_provided_target(rustc, target))
3456+
.unwrap_or_else(|| "7.0".into()),
3457+
AppleOs::WatchOs => env::var("WATCHOS_DEPLOYMENT_TARGET")
3458+
.ok()
3459+
.or_else(|| rustc_provided_target(rustc, target))
3460+
.unwrap_or_else(|| "5.0".into()),
3461+
}
3462+
}
3463+
34023464
fn cuda_file_count(&self) -> usize {
34033465
self.files
34043466
.iter()
@@ -3786,6 +3848,22 @@ fn command_add_output_file(
37863848
}
37873849
}
37883850

3851+
#[derive(Clone, Copy)]
3852+
enum AppleOs {
3853+
MacOs,
3854+
Ios,
3855+
WatchOs,
3856+
}
3857+
impl std::fmt::Debug for AppleOs {
3858+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
3859+
match self {
3860+
AppleOs::MacOs => f.write_str("macOS"),
3861+
AppleOs::Ios => f.write_str("iOS"),
3862+
AppleOs::WatchOs => f.write_str("WatchOS"),
3863+
}
3864+
}
3865+
}
3866+
37893867
// Use by default minimum available API level
37903868
// See note about naming here
37913869
// https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md#Clang

tests/test.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,3 +475,21 @@ fn asm_flags() {
475475
test.cmd(1).must_have("--abc");
476476
test.cmd(2).must_have("--abc");
477477
}
478+
479+
#[test]
480+
fn gnu_apple_darwin() {
481+
for (arch, version) in &[("x86_64", "10.7"), ("aarch64", "11.0")] {
482+
let target = format!("{}-apple-darwin", arch);
483+
let test = Test::gnu();
484+
test.gcc()
485+
.target(&target)
486+
.host(&target)
487+
// Avoid test maintainence when minimum supported OSes change.
488+
.__set_env("MACOSX_DEPLOYMENT_TARGET", version)
489+
.file("foo.c")
490+
.compile("foo");
491+
492+
test.cmd(0)
493+
.must_have(format!("-mmacosx-version-min={}", version));
494+
}
495+
}

0 commit comments

Comments
 (0)