Try audodetecting sysroot when building Darwin on Darwin

This is now no longer limited to targeting macOS natively but also
tries to detect the sysroot when targeting different Apple platforms
from macOS; for instance targeting iPhone Simulator from macOS. In
this case, Zig will try detecting the SDK path by invoking
`xcrun --sdk iphonesimulator --show-sdk-path`, and if the command
fails because the SDK doesn't exist (case when having CLT installed only)
or not having either Xcode or CLT installed, we simply return null
signaling that the user has to provide the sysroot themselves.
This commit is contained in:
Jakub Konka 2021-08-06 11:36:40 +02:00
parent 2371a63bd4
commit e9bee08f88
5 changed files with 60 additions and 37 deletions

View File

@ -13,12 +13,10 @@ const assert = std.debug.assert;
const process = std.process;
const Target = std.Target;
const CrossTarget = std.zig.CrossTarget;
const macos = @import("system/macos.zig");
const native_endian = std.Target.current.cpu.arch.endian();
const linux = @import("system/linux.zig");
pub const windows = @import("system/windows.zig");
pub const getSDKPath = macos.getSDKPath;
pub const darwin = @import("system/darwin.zig");
pub const NativePaths = struct {
include_dirs: ArrayList([:0]u8),
@ -255,7 +253,7 @@ pub const NativeTargetInfo = struct {
os.version_range.windows.min = detected_version;
os.version_range.windows.max = detected_version;
},
.macos => try macos.detect(&os),
.macos => try darwin.macos.detect(&os),
.freebsd, .netbsd, .dragonfly => {
const key = switch (Target.current.os.tag) {
.freebsd => "kern.osreldate",
@ -972,7 +970,7 @@ pub const NativeTargetInfo = struct {
switch (std.Target.current.os.tag) {
.linux => return linux.detectNativeCpuAndFeatures(),
.macos => return macos.detectNativeCpuAndFeatures(),
.macos => return darwin.macos.detectNativeCpuAndFeatures(),
else => {},
}
@ -983,6 +981,6 @@ pub const NativeTargetInfo = struct {
};
test {
_ = @import("system/macos.zig");
_ = @import("system/darwin.zig");
_ = @import("system/linux.zig");
}

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2021 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("std");
const mem = std.mem;
const Allocator = mem.Allocator;
const Target = std.Target;
pub const macos = @import("darwin/macos.zig");
/// Detect SDK path on Darwin.
/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which result can be used to specify
/// `--sysroot` of the compiler.
/// The caller needs to free the resulting path slice.
pub fn getSDKPath(allocator: *Allocator, target: Target) !?[]u8 {
const is_simulator_abi = target.abi == .simulator;
const sdk = switch (target.os.tag) {
.macos => "macosx",
.ios => if (is_simulator_abi) "iphonesimulator" else "iphoneos",
.watchos => if (is_simulator_abi) "watchsimulator" else "watchos",
.tvos => if (is_simulator_abi) "appletvsimulator" else "appletvos",
else => return null,
};
const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" };
const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
}
if (result.stderr.len != 0 or result.term.Exited != 0) {
// We don't actually care if there were errors as this is best-effort check anyhow
// and in the worst case the user can specify the sysroot manually.
return null;
}
const sysroot = try allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n"));
return sysroot;
}
test "" {
_ = @import("darwin/macos.zig");
}

View File

@ -408,28 +408,6 @@ fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version)
try testing.expectEqualStrings(s_expected, s_got);
}
/// Detect SDK path on Darwin.
/// Calls `xcrun --show-sdk-path` which result can be used to specify
/// `-syslibroot` param of the linker.
/// The caller needs to free the resulting path slice.
pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {
assert(Target.current.isDarwin());
const argv = &[_][]const u8{ "xcrun", "--show-sdk-path" };
const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
}
if (result.stderr.len != 0) {
std.log.err("unexpected 'xcrun --show-sdk-path' stderr: {s}", .{result.stderr});
}
if (result.term.Exited != 0) {
return error.ProcessTerminated;
}
const syslibroot = mem.trimRight(u8, result.stdout, "\r\n");
return mem.dupe(allocator, u8, syslibroot);
}
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
var cpu_family: os.CPUFAMILY = undefined;
var len: usize = @sizeOf(os.CPUFAMILY);

View File

@ -944,8 +944,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (options.sysroot) |sysroot| {
break :blk sysroot;
} else if (darwin_can_use_system_sdk) {
const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null;
break :blk try std.zig.system.darwin.getSDKPath(arena, options.target);
} else {
break :blk null;
}

View File

@ -1678,7 +1678,9 @@ fn buildOutputType(
want_native_include_dirs = true;
}
if (sysroot == null and cross_target.isNativeOs() and
const is_darwin_on_darwin = (comptime std.Target.current.isDarwin()) and cross_target.isDarwin();
if (sysroot == null and (cross_target.isNativeOs() or is_darwin_on_darwin) and
(system_libs.items.len != 0 or want_native_include_dirs))
{
const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| {
@ -1689,16 +1691,18 @@ fn buildOutputType(
}
const has_sysroot = if (comptime std.Target.current.isDarwin()) outer: {
const min = target_info.target.os.getVersionRange().semver.min;
const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14);
if (at_least_mojave) {
const sdk_path = try std.zig.system.getSDKPath(arena);
const should_get_sdk_path = if (cross_target.isNativeOs() and target_info.target.os.tag == .macos) inner: {
const min = target_info.target.os.getVersionRange().semver.min;
const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14);
break :inner at_least_mojave;
} else true;
if (!should_get_sdk_path) break :outer false;
if (try std.zig.system.darwin.getSDKPath(arena, target_info.target)) |sdk_path| {
try clang_argv.ensureCapacity(clang_argv.items.len + 2);
clang_argv.appendAssumeCapacity("-isysroot");
clang_argv.appendAssumeCapacity(sdk_path);
break :outer true;
}
break :outer false;
} else break :outer false;
} else false;
try clang_argv.ensureCapacity(clang_argv.items.len + paths.include_dirs.items.len * 2);