diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index ae8212bb..13daa9c7 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -44,7 +44,17 @@ set(SPDLOG_NO_EXCEPTIONS ON CACHE BOOL "" FORCE) add_subdirectory(spdlog EXCLUDE_FROM_ALL) if (NOT TARGET FFmpeg::ffmpeg) - if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$") + # On macOS the target arch is driven by CMAKE_OSX_ARCHITECTURES, not the host + # CMAKE_SYSTEM_PROCESSOR (which reports arm64 even for an x86_64/Rosetta build). + if(APPLE AND CMAKE_OSX_ARCHITECTURES) + if(CMAKE_OSX_ARCHITECTURES MATCHES "^(x86_64)$") + set(ARCHITECTURE x86_64) + elseif(CMAKE_OSX_ARCHITECTURES MATCHES "^(arm64)$") + set(ARCHITECTURE arm64) + else() + set(ARCHITECTURE x86_64 arm64) # universal + endif() + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$") set(ARCHITECTURE arm64) else() set(ARCHITECTURE x86_64) diff --git a/3rdparty/cpuinfo/CMakeLists.txt b/3rdparty/cpuinfo/CMakeLists.txt index 92d218e7..609bd065 100644 --- a/3rdparty/cpuinfo/CMakeLists.txt +++ b/3rdparty/cpuinfo/CMakeLists.txt @@ -5,7 +5,14 @@ set(cpuinfo_src deps/clog/src/clog.c ) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$") +# On Apple the target arch is driven by CMAKE_OSX_ARCHITECTURES, not the host +# CMAKE_SYSTEM_PROCESSOR (which is arm64 even for an x86_64/Rosetta build). +set(CPUINFO_TARGET_PROC "${CMAKE_SYSTEM_PROCESSOR}") +if(APPLE AND CMAKE_OSX_ARCHITECTURES) + list(GET CMAKE_OSX_ARCHITECTURES 0 CPUINFO_TARGET_PROC) +endif() + +if(CPUINFO_TARGET_PROC MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$") list(APPEND cpuinfo_src src/x86/init.c src/x86/info.c @@ -19,11 +26,13 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$") src/x86/cache/deterministic.c) if(LINUX OR ANDROID) list(APPEND cpuinfo_src src/x86/linux/init.c src/x86/linux/cpuinfo.c) + elseif(APPLE) + list(APPEND cpuinfo_src src/x86/mach/init.c src/mach/topology.c) else() list(APPEND cpuinfo_src src/x86/windows/init.c) endif() - -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv[5-8].*|aarch64|arm64)$") + +elseif(CPUINFO_TARGET_PROC MATCHES "^(armv[5-8].*|aarch64|arm64)$") list(APPEND cpuinfo_src src/arm/uarch.c src/arm/cache.c) if(LINUX OR ANDROID) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3cc7b0ae..601e14f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,8 +10,8 @@ if(CMAKE_SYSTEM_NAME MATCHES ".*Linux") set(LINUX TRUE) endif() -if (NOT (WIN32 OR LINUX)) - message(FATAL_ERROR "only Windows and Linux builds are supported") +if (NOT (WIN32 OR LINUX OR APPLE)) + message(FATAL_ERROR "only Windows, Linux, and macOS builds are supported") endif() set(CMAKE_CXX_STANDARD 20) @@ -45,8 +45,9 @@ else() set(KYTY_BUILD KYTY_BUILD_RELEASE) endif() -if(LINUX) - set(KYTY_PLATFORM KYTY_PLATFORM_LINUX) +if(LINUX OR APPLE) + # macOS rides the POSIX/Linux code paths until it gets a dedicated platform + set(KYTY_PLATFORM KYTY_PLATFORM_LINUX) else() set(KYTY_PLATFORM KYTY_PLATFORM_WINDOWS) endif() @@ -63,6 +64,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") if(WIN32 AND KYTY_CXX_COMPILER_NAME STREQUAL "clang-cl") set(KYTY_CLANG_CL TRUE) set(KYTY_LINKER LLD_LINK) + elseif(APPLE) + set(KYTY_LINKER LD64) # Apple's default linker; lld flags don't apply else() set(KYTY_LINKER LLD) endif() @@ -461,6 +464,18 @@ endif() add_dependencies(kyty_emulator KytyGitVersion) +if(APPLE) + # The emulator writes x86-64 trampolines/PLT stubs into memory and executes them, and + # runs guest code under Rosetta. That requires the JIT / unsigned-executable-memory + # entitlements, so re-sign the binary after every link (an unsigned/relinked binary + # reverts to the hardened defaults and aborts when it first executes written code). + add_custom_command(TARGET kyty_emulator POST_BUILD + COMMAND codesign -s - --force --options runtime + --entitlements "${CMAKE_CURRENT_SOURCE_DIR}/macos_jit.entitlements" + $ + COMMENT "Codesign kyty_emulator with JIT entitlements (macOS)") +endif() + install(TARGETS kyty_emulator DESTINATION .) if(KYTY_BUILD_LAUNCHER) add_subdirectory(launcher) diff --git a/src/macos_jit.entitlements b/src/macos_jit.entitlements new file mode 100644 index 00000000..efdcbccb --- /dev/null +++ b/src/macos_jit.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.disable-library-validation + + + diff --git a/src/utils.cmake b/src/utils.cmake index 778d54f0..911de25c 100644 --- a/src/utils.cmake +++ b/src/utils.cmake @@ -68,7 +68,15 @@ set(KYTY_WARNINGS_ARE_ERRORS OFF) set(KYTY_C_FLAGS "") set(KYTY_CPP_FLAGS "") -SET(CMAKE_NINJA_FORCE_RESPONSE_FILE 1 CACHE INTERNAL "") +# Apple's /usr/bin/ar does not understand @response-file syntax, and macOS has a +# large ARG_MAX so response files aren't needed. Note: the Ninja generator forces a +# response file whenever CMAKE_NINJA_FORCE_RESPONSE_FILE is *defined* (it tests +# definedness, not the value), so on Apple it must be fully unset, not set to 0. +if(APPLE) + unset(CMAKE_NINJA_FORCE_RESPONSE_FILE CACHE) +else() + SET(CMAKE_NINJA_FORCE_RESPONSE_FILE 1 CACHE INTERNAL "") +endif() if(KYTY_CLANG_CL) if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")