From b613210140f649b11232fae8bad16867d122d0cb Mon Sep 17 00:00:00 2001 From: Stephen Gutekanst Date: Mon, 29 Nov 2021 12:54:23 -0700 Subject: [PATCH] compiler_rt: implement __isPlatformVersionAtLeast (Objective-C @available expressions) for Darwin (#10232) --- CMakeLists.txt | 1 + lib/std/special/compiler_rt.zig | 6 +++ .../special/compiler_rt/os_version_check.zig | 50 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 lib/std/special/compiler_rt/os_version_check.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index f9800b4e9b..8f4cecd8f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,6 +497,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muloti4.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig" + "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/os_version_check.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcountdi2.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/shift.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/stack_probe.zig" diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index d83d143aef..ee32e49282 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -7,6 +7,7 @@ const abi = builtin.abi; const is_gnu = abi.isGnu(); const is_mingw = os_tag == .windows and is_gnu; +const is_darwin = std.Target.Os.Tag.isDarwin(os_tag); const linkage = if (is_test) std.builtin.GlobalLinkage.Internal @@ -336,6 +337,11 @@ comptime { const __popcountdi2 = @import("compiler_rt/popcountdi2.zig").__popcountdi2; @export(__popcountdi2, .{ .name = "__popcountdi2", .linkage = linkage }); + if (is_darwin) { + const __isPlatformVersionAtLeast = @import("compiler_rt/os_version_check.zig").__isPlatformVersionAtLeast; + @export(__isPlatformVersionAtLeast, .{ .name = "__isPlatformVersionAtLeast", .linkage = linkage }); + } + const __mulsi3 = @import("compiler_rt/int.zig").__mulsi3; @export(__mulsi3, .{ .name = "__mulsi3", .linkage = linkage }); const __muldi3 = @import("compiler_rt/muldi3.zig").__muldi3; diff --git a/lib/std/special/compiler_rt/os_version_check.zig b/lib/std/special/compiler_rt/os_version_check.zig new file mode 100644 index 0000000000..d7408e2d14 --- /dev/null +++ b/lib/std/special/compiler_rt/os_version_check.zig @@ -0,0 +1,50 @@ +const testing = @import("std").testing; +const builtin = @import("builtin"); + +// Ported from llvm-project 13.0.0 d7b669b3a30345cfcdb2fde2af6f48aa4b94845d +// +// https://github.com/llvm/llvm-project/blob/llvmorg-13.0.0/compiler-rt/lib/builtins/os_version_check.c + +// The compiler generates calls to __isPlatformVersionAtLeast() when Objective-C's @available +// function is invoked. +// +// Old versions of clang would instead emit calls to __isOSVersionAtLeast(), which is still +// supported in clang's compiler-rt implementation today in case anyone tries to link an object file +// produced with an old clang version. This requires dynamically loading frameworks, parsing a +// system plist file, and generally adds a fair amount of complexity to the implementation and so +// our implementation differs by simply removing that backwards compatability support. We only use +// the newer codepath, which merely calls out to the Darwin _availability_version_check API which is +// available on macOS 10.15+, iOS 13+, tvOS 13+ and watchOS 6+. + +inline fn constructVersion(major: u32, minor: u32, subminor: u32) u32 { + return ((major & 0xffff) << 16) | ((minor & 0xff) << 8) | (subminor & 0xff); +} + +// Darwin-only +pub fn __isPlatformVersionAtLeast(platform: u32, major: u32, minor: u32, subminor: u32) callconv(.C) i32 { + return @boolToInt(_availability_version_check(1, &[_]dyld_build_version_t{ + .{ + .platform = platform, + .version = constructVersion(major, minor, subminor), + }, + })); +} + +// _availability_version_check darwin API support. +const dyld_platform_t = u32; +const dyld_build_version_t = extern struct { + platform: dyld_platform_t, + version: u32, +}; +// Darwin-only +extern "c" fn _availability_version_check(count: u32, versions: [*c]const dyld_build_version_t) bool; + +test "isPlatformVersionAtLeast" { + if (!builtin.os.tag.isDarwin()) return error.SkipZigTest; + + // Note: this test depends on the actual host OS version since it is merely calling into the + // native Darwin API. + const macos_platform_constant = 1; + try testing.expect(__isPlatformVersionAtLeast(macos_platform_constant, 10, 0, 15) == 1); + try testing.expect(__isPlatformVersionAtLeast(macos_platform_constant, 99, 0, 0) == 0); +}