diff --git a/CHANGELOG b/CHANGELOG index e51a2cd78..fb91b3557 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -236,7 +236,7 @@ Fixes builds every library and Singe itself. The results are a Linux binary that runs on glibc 2.28 or newer, a Windows 10 or newer binary, a 64-bit Raspberry Pi OS (bullseye or newer) binary and a macOS 13 or - newer Apple silicon binary. The toolchains repository is no longer + newer universal (Apple silicon and Intel) binary. The toolchains repository is no longer needed. See INSTALL. diff --git a/CMakePresets.json b/CMakePresets.json index b5f29a6a9..edbfc689f 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -76,6 +76,18 @@ "SINGE_CROSS_OS": "darwin", "SINGE_SUFFIX": "" } + }, + { + "name": "macos-x86_64", + "displayName": "macOS Intel (zig)", + "inherits": "base", + "binaryDir": "${sourceDir}/.builddir/macos/x86_64/superbuild", + "toolchainFile": "${sourceDir}/cmake/zig/x86_64-macos.cmake", + "cacheVariables": { + "SINGE_TRIPLE": "x86_64-apple-darwin22.4", + "SINGE_CROSS_OS": "darwin", + "SINGE_SUFFIX": "" + } } ], "buildPresets": [ @@ -98,6 +110,10 @@ { "name": "macos-aarch64", "configurePreset": "macos-aarch64" + }, + { + "name": "macos-x86_64", + "configurePreset": "macos-x86_64" } ] } diff --git a/INSTALL b/INSTALL index 015a9968b..ff1512559 100644 --- a/INSTALL +++ b/INSTALL @@ -90,7 +90,11 @@ put a tarball holding a single MacOSX*.sdk directory at that), or point SINGE_MACOS_SDK at an unpacked SDK. SINGE_MACOS_SDK_URL and SINGE_MACOS_SDK_SHA256 pick a different mirror. Then: - ./build-all.sh macos aarch64 + ./build-all.sh macos universal + +builds the Apple silicon and Intel presets (macos-aarch64, macos-x86_64) +and joins them with llvm-lipo into Singe-v3.00-Macos-universal. Either +architecture alone is ./build-all.sh macos aarch64 or x86_64. The Raspberry Pi build (64-bit Raspberry Pi OS, glibc 2.31 or newer) also uses zig. The platform headers and libraries it links against are diff --git a/build-all.sh b/build-all.sh index f50d4ff81..ab1fdf23a 100755 --- a/build-all.sh +++ b/build-all.sh @@ -41,6 +41,14 @@ function buildAll() { # Every platform builds with the zig the build fetches itself; the Pi preset also fetches its # platform packages and macOS needs the Apple SDK tarball (see INSTALL). + # "macos universal" builds both macOS presets and joins them with llvm-lipo. + if [[ "${OS}" == "macos" && "${ARCH}" == "universal" ]]; then + buildAll macos aarch64 "$@" + buildAll macos x86_64 "$@" + cmake -P cmake/zig/macosUniversal.cmake + return + fi + cmake --preset ${OS}-${ARCH} cmake --build --preset ${OS}-${ARCH} "$@" } @@ -83,7 +91,7 @@ if [[ $# -ge 2 ]]; then buildAll "$@" 2>&1 | tee ${G_BUILDDIR}/$1-$2.log else buildAll linux x86_64 2>&1 | tee ${G_BUILDDIR}/linux-x86_64.log - buildAll macos aarch64 2>&1 | tee ${G_BUILDDIR}/macos-aarch64.log + buildAll macos universal 2>&1 | tee ${G_BUILDDIR}/macos-universal.log buildAll pi aarch64 2>&1 | tee ${G_BUILDDIR}/pi-aarch64.log buildAll windows x86_64 2>&1 | tee ${G_BUILDDIR}/windows-x86_64.log fi diff --git a/cmake/Superbuild.cmake b/cmake/Superbuild.cmake index eeca60232..7373c18a1 100644 --- a/cmake/Superbuild.cmake +++ b/cmake/Superbuild.cmake @@ -257,14 +257,14 @@ if(SINGE_ZIG_TARGET) # FFmpeg only uses nm to learn the symbol prefix. The host's binutils nm reads x86 ELF and PE # objects but not aarch64 or Mach-O ones; the prefix is empty on Linux either way, and on macOS # (where it is an underscore) llvm-nm from Debian's llvm package reads Mach-O. - if(KANGAROO_ARCH STREQUAL "x86_64") - list(APPEND ffmpegTools --nm=nm) - elseif(KANGAROO_OS STREQUAL "macos") + if(KANGAROO_OS STREQUAL "macos") find_program(SINGE_LLVM_NM NAMES llvm-nm llvm-nm-21 llvm-nm-20 llvm-nm-19 llvm-nm-18 llvm-nm-17 llvm-nm-16 llvm-nm-15) if(NOT SINGE_LLVM_NM) message(FATAL_ERROR "llvm-nm is needed for the macOS FFmpeg build (apt-get install llvm).") endif() list(APPEND ffmpegTools --nm=${SINGE_LLVM_NM}) + elseif(KANGAROO_ARCH STREQUAL "x86_64") + list(APPEND ffmpegTools --nm=nm) endif() else() set(ffmpegTools --cross-prefix=${SINGE_TRIPLE}- --cc=${SB_CC} --cxx=${SB_CXX} --ranlib=${SB_RANLIB}) diff --git a/cmake/zig/aarch64-macos.cmake b/cmake/zig/aarch64-macos.cmake index a301c3b19..66b5f55d0 100644 --- a/cmake/zig/aarch64-macos.cmake +++ b/cmake/zig/aarch64-macos.cmake @@ -17,83 +17,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # -# macOS on Apple silicon with zig as the compiler. zig carries the macOS libc headers and the -# libSystem stub itself; everything else (Cocoa, CoreAudio, VideoToolbox, Metal and the rest of -# the frameworks, libc++, libiconv) comes from an Apple SDK, which Apple does not let a build -# script fetch. The SDK is expected, in this order: -# 1. an unpacked SDK at SINGE_MACOS_SDK (default .builddir/toolchains/MacOSX.sdk); -# 2. a tarball at .builddir/toolchains/MacOSX.sdk.tar.xz, unpacked on first use; -# 3. SINGE_MACOS_SDK_URL (with SINGE_MACOS_SDK_SHA256), downloaded and unpacked on first use; -# the default points at the community mirror osxcross users share (github.com/joseluisq/ -# macosx-sdks), pinned to one SDK release and its published SHA-256. -# See INSTALL for how to make the tarball from Xcode instead. +# macOS on Apple silicon; everything is in macos.cmake. -include(${CMAKE_CURRENT_LIST_DIR}/zig.cmake) - -set(CMAKE_SYSTEM_NAME Darwin) +set(SINGE_MACOS_ARCH aarch64) set(CMAKE_SYSTEM_PROCESSOR arm64) - -# Oldest macOS the binary runs on (Ventura: Intel Macs from 2017 and every Apple silicon Mac). -set(SINGE_MACOS_VERSION 13.0) - -get_filename_component(sdkToolchains ${CMAKE_CURRENT_LIST_DIR}/../../.builddir/toolchains ABSOLUTE) -set(SINGE_MACOS_SDK ${sdkToolchains}/MacOSX.sdk CACHE PATH "Unpacked Apple SDK for the macOS build") -set(SINGE_MACOS_SDK_URL "https://github.com/joseluisq/macosx-sdks/releases/download/15.5/MacOSX15.5.sdk.tar.xz" CACHE STRING "Where to fetch the Apple SDK tarball from; empty to never download") -set(SINGE_MACOS_SDK_SHA256 "c15cf0f3f17d714d1aa5a642da8e118db53d79429eb015771ba816aa7c6c1cbd" CACHE STRING "SHA-256 of that tarball; empty to skip the check") -set(sdkTarball ${sdkToolchains}/MacOSX.sdk.tar.xz) -if(NOT EXISTS ${SINGE_MACOS_SDK}/System/Library/Frameworks/Cocoa.framework) - if((NOT EXISTS ${sdkTarball}) AND SINGE_MACOS_SDK_URL) - message(STATUS "Downloading the Apple SDK from ${SINGE_MACOS_SDK_URL}") - file(MAKE_DIRECTORY ${sdkToolchains}) - if(SINGE_MACOS_SDK_SHA256) - file(DOWNLOAD ${SINGE_MACOS_SDK_URL} ${sdkTarball} EXPECTED_HASH SHA256=${SINGE_MACOS_SDK_SHA256} STATUS status) - else() - file(DOWNLOAD ${SINGE_MACOS_SDK_URL} ${sdkTarball} STATUS status) - endif() - list(GET status 0 code) - if(NOT code EQUAL 0) - message(FATAL_ERROR "Apple SDK download failed: ${status}") - endif() - endif() - if(EXISTS ${sdkTarball}) - message(STATUS "Unpacking ${sdkTarball}") - set(sdkUnpack ${sdkToolchains}/MacOSX.sdk.unpack) - file(REMOVE_RECURSE ${sdkUnpack}) - file(ARCHIVE_EXTRACT INPUT ${sdkTarball} DESTINATION ${sdkUnpack}) - file(GLOB sdkFound LIST_DIRECTORIES true ${sdkUnpack}/*.sdk ${sdkUnpack}/*/*.sdk) - list(LENGTH sdkFound sdkCount) - if(NOT sdkCount EQUAL 1) - message(FATAL_ERROR "${sdkTarball} should hold exactly one MacOSX*.sdk directory; found ${sdkCount}.") - endif() - file(RENAME ${sdkFound} ${SINGE_MACOS_SDK}) - file(REMOVE_RECURSE ${sdkUnpack}) - endif() -endif() -if(NOT EXISTS ${SINGE_MACOS_SDK}/System/Library/Frameworks/Cocoa.framework) - message(FATAL_ERROR "No Apple SDK at ${SINGE_MACOS_SDK}. Put an SDK tarball at ${sdkTarball} (see INSTALL), or set SINGE_MACOS_SDK to an unpacked SDK, or SINGE_MACOS_SDK_URL to fetch one.") -endif() - -# No --sysroot: zig would then prefix every -L path with it, the superbuild's own lib directory -# included. The SDK is named outright instead: its usr/include (libDER and other non-libc pieces) -# after zig's own libc headers, its frameworks, and its stub libraries. The SDK's CMTag.h uses two -# macOS 14 types without an availability guard, and FFmpeg's configure makes that an error with -# -Werror=partial-availability; the trailing -Wno-unguarded-availability-new wins over it. -singeZigToolchain(aarch64-macos.${SINGE_MACOS_VERSION} "-idirafter ${SINGE_MACOS_SDK}/usr/include -F${SINGE_MACOS_SDK}/System/Library/Frameworks -L${SINGE_MACOS_SDK}/usr/lib -Wno-unguarded-availability-new") -# SDL3 compiles Objective-C, which the same zig wrappers handle, and CMake's Darwin support insists -# on an install_name_tool even though nothing here links dynamically; llvm's stands in. -set(CMAKE_OBJC_COMPILER ${CMAKE_C_COMPILER} CACHE FILEPATH "" FORCE) -set(CMAKE_OBJCXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE FILEPATH "" FORCE) -find_program(SINGE_INSTALL_NAME_TOOL NAMES llvm-install-name-tool llvm-install-name-tool-21 llvm-install-name-tool-20 llvm-install-name-tool-19 llvm-install-name-tool-18 llvm-install-name-tool-17 llvm-install-name-tool-16 llvm-install-name-tool-15) -if(NOT SINGE_INSTALL_NAME_TOOL) - message(FATAL_ERROR "llvm-install-name-tool is needed for the macOS build (apt-get install llvm).") -endif() -set(CMAKE_INSTALL_NAME_TOOL ${SINGE_INSTALL_NAME_TOOL} CACHE FILEPATH "" FORCE) -set(CMAKE_OSX_SYSROOT "" CACHE PATH "Left empty; the wrappers name the SDK themselves" FORCE) -set(CMAKE_OSX_ARCHITECTURES "" CACHE STRING "Left empty; the zig target names the architecture" FORCE) -set(CMAKE_FIND_ROOT_PATH ${SINGE_MACOS_SDK}) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) -set(KANGAROO_OS macos) -set(KANGAROO_ARCH aarch64) +include(${CMAKE_CURRENT_LIST_DIR}/macos.cmake) diff --git a/cmake/zig/macos.cmake b/cmake/zig/macos.cmake new file mode 100644 index 000000000..88689d7e4 --- /dev/null +++ b/cmake/zig/macos.cmake @@ -0,0 +1,99 @@ +# +# Singe 3 +# Copyright (C) 2006-2026 Scott Duensing +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public Licens +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# macOS with zig as the compiler, shared by the aarch64 and x86_64 toolchain files (which set +# SINGE_MACOS_ARCH and CMAKE_SYSTEM_PROCESSOR before including this). zig carries the macOS libc +# headers and the libSystem stub itself; everything else (Cocoa, CoreAudio, VideoToolbox, Metal and the rest of +# the frameworks, libc++, libiconv) comes from an Apple SDK, which Apple does not let a build +# script fetch. The SDK is expected, in this order: +# 1. an unpacked SDK at SINGE_MACOS_SDK (default .builddir/toolchains/MacOSX.sdk); +# 2. a tarball at .builddir/toolchains/MacOSX.sdk.tar.xz, unpacked on first use; +# 3. SINGE_MACOS_SDK_URL (with SINGE_MACOS_SDK_SHA256), downloaded and unpacked on first use; +# the default points at the community mirror osxcross users share (github.com/joseluisq/ +# macosx-sdks), pinned to one SDK release and its published SHA-256. +# See INSTALL for how to make the tarball from Xcode instead. + +include(${CMAKE_CURRENT_LIST_DIR}/zig.cmake) + +set(CMAKE_SYSTEM_NAME Darwin) + +# Oldest macOS the binary runs on (Ventura: Intel Macs from 2017 and every Apple silicon Mac). +set(SINGE_MACOS_VERSION 13.0) + +get_filename_component(sdkToolchains ${CMAKE_CURRENT_LIST_DIR}/../../.builddir/toolchains ABSOLUTE) +set(SINGE_MACOS_SDK ${sdkToolchains}/MacOSX.sdk CACHE PATH "Unpacked Apple SDK for the macOS build") +set(SINGE_MACOS_SDK_URL "https://github.com/joseluisq/macosx-sdks/releases/download/15.5/MacOSX15.5.sdk.tar.xz" CACHE STRING "Where to fetch the Apple SDK tarball from; empty to never download") +set(SINGE_MACOS_SDK_SHA256 "c15cf0f3f17d714d1aa5a642da8e118db53d79429eb015771ba816aa7c6c1cbd" CACHE STRING "SHA-256 of that tarball; empty to skip the check") +set(sdkTarball ${sdkToolchains}/MacOSX.sdk.tar.xz) +if(NOT EXISTS ${SINGE_MACOS_SDK}/System/Library/Frameworks/Cocoa.framework) + if((NOT EXISTS ${sdkTarball}) AND SINGE_MACOS_SDK_URL) + message(STATUS "Downloading the Apple SDK from ${SINGE_MACOS_SDK_URL}") + file(MAKE_DIRECTORY ${sdkToolchains}) + if(SINGE_MACOS_SDK_SHA256) + file(DOWNLOAD ${SINGE_MACOS_SDK_URL} ${sdkTarball} EXPECTED_HASH SHA256=${SINGE_MACOS_SDK_SHA256} STATUS status) + else() + file(DOWNLOAD ${SINGE_MACOS_SDK_URL} ${sdkTarball} STATUS status) + endif() + list(GET status 0 code) + if(NOT code EQUAL 0) + message(FATAL_ERROR "Apple SDK download failed: ${status}") + endif() + endif() + if(EXISTS ${sdkTarball}) + message(STATUS "Unpacking ${sdkTarball}") + set(sdkUnpack ${sdkToolchains}/MacOSX.sdk.unpack) + file(REMOVE_RECURSE ${sdkUnpack}) + file(ARCHIVE_EXTRACT INPUT ${sdkTarball} DESTINATION ${sdkUnpack}) + file(GLOB sdkFound LIST_DIRECTORIES true ${sdkUnpack}/*.sdk ${sdkUnpack}/*/*.sdk) + list(LENGTH sdkFound sdkCount) + if(NOT sdkCount EQUAL 1) + message(FATAL_ERROR "${sdkTarball} should hold exactly one MacOSX*.sdk directory; found ${sdkCount}.") + endif() + file(RENAME ${sdkFound} ${SINGE_MACOS_SDK}) + file(REMOVE_RECURSE ${sdkUnpack}) + endif() +endif() +if(NOT EXISTS ${SINGE_MACOS_SDK}/System/Library/Frameworks/Cocoa.framework) + message(FATAL_ERROR "No Apple SDK at ${SINGE_MACOS_SDK}. Put an SDK tarball at ${sdkTarball} (see INSTALL), or set SINGE_MACOS_SDK to an unpacked SDK, or SINGE_MACOS_SDK_URL to fetch one.") +endif() + +# No --sysroot: zig would then prefix every -L path with it, the superbuild's own lib directory +# included. The SDK is named outright instead: its usr/include (libDER and other non-libc pieces) +# after zig's own libc headers, its frameworks, and its stub libraries. The SDK's CMTag.h uses two +# macOS 14 types without an availability guard, and FFmpeg's configure makes that an error with +# -Werror=partial-availability; the trailing -Wno-unguarded-availability-new wins over it. +singeZigToolchain(${SINGE_MACOS_ARCH}-macos.${SINGE_MACOS_VERSION} "-idirafter ${SINGE_MACOS_SDK}/usr/include -F${SINGE_MACOS_SDK}/System/Library/Frameworks -L${SINGE_MACOS_SDK}/usr/lib -Wno-unguarded-availability-new") +# SDL3 compiles Objective-C, which the same zig wrappers handle, and CMake's Darwin support insists +# on an install_name_tool even though nothing here links dynamically; llvm's stands in. +set(CMAKE_OBJC_COMPILER ${CMAKE_C_COMPILER} CACHE FILEPATH "" FORCE) +set(CMAKE_OBJCXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE FILEPATH "" FORCE) +find_program(SINGE_INSTALL_NAME_TOOL NAMES llvm-install-name-tool llvm-install-name-tool-21 llvm-install-name-tool-20 llvm-install-name-tool-19 llvm-install-name-tool-18 llvm-install-name-tool-17 llvm-install-name-tool-16 llvm-install-name-tool-15) +if(NOT SINGE_INSTALL_NAME_TOOL) + message(FATAL_ERROR "llvm-install-name-tool is needed for the macOS build (apt-get install llvm).") +endif() +set(CMAKE_INSTALL_NAME_TOOL ${SINGE_INSTALL_NAME_TOOL} CACHE FILEPATH "" FORCE) +set(CMAKE_OSX_SYSROOT "" CACHE PATH "Left empty; the wrappers name the SDK themselves" FORCE) +set(CMAKE_OSX_ARCHITECTURES "" CACHE STRING "Left empty; the zig target names the architecture" FORCE) +set(CMAKE_FIND_ROOT_PATH ${SINGE_MACOS_SDK}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(KANGAROO_OS macos) +set(KANGAROO_ARCH ${SINGE_MACOS_ARCH}) diff --git a/cmake/zig/macosUniversal.cmake b/cmake/zig/macosUniversal.cmake new file mode 100644 index 000000000..eafaec429 --- /dev/null +++ b/cmake/zig/macosUniversal.cmake @@ -0,0 +1,38 @@ +# +# Singe 3 +# Copyright (C) 2006-2026 Scott Duensing +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public Licens +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# Joins the Apple silicon and Intel Singe binaries into one universal binary with llvm-lipo. +# Run as: cmake -P cmake/zig/macosUniversal.cmake (after both macOS presets have built) + +get_filename_component(buildDir ${CMAKE_CURRENT_LIST_DIR}/../../.builddir ABSOLUTE) +file(GLOB armBinary ${buildDir}/Singe-v*-Macos-aarch64) +file(GLOB intelBinary ${buildDir}/Singe-v*-Macos-x86_64) +if(NOT armBinary OR NOT intelBinary) + message(FATAL_ERROR "Build the macos-aarch64 and macos-x86_64 presets first.") +endif() +string(REPLACE "-aarch64" "-universal" universalBinary ${armBinary}) +find_program(SINGE_LIPO NAMES llvm-lipo llvm-lipo-21 llvm-lipo-20 llvm-lipo-19 llvm-lipo-18 llvm-lipo-17 llvm-lipo-16 llvm-lipo-15) +if(NOT SINGE_LIPO) + message(FATAL_ERROR "llvm-lipo is needed to make the universal binary (apt-get install llvm).") +endif() +execute_process(COMMAND ${SINGE_LIPO} -create ${armBinary} ${intelBinary} -output ${universalBinary} RESULT_VARIABLE code) +if(NOT code EQUAL 0) + message(FATAL_ERROR "llvm-lipo failed.") +endif() +message(STATUS "Wrote ${universalBinary}") diff --git a/cmake/zig/x86_64-macos.cmake b/cmake/zig/x86_64-macos.cmake new file mode 100644 index 000000000..c51e43d93 --- /dev/null +++ b/cmake/zig/x86_64-macos.cmake @@ -0,0 +1,24 @@ +# +# Singe 3 +# Copyright (C) 2006-2026 Scott Duensing +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public Licens +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# macOS on Intel; everything is in macos.cmake. + +set(SINGE_MACOS_ARCH x86_64) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +include(${CMAKE_CURRENT_LIST_DIR}/macos.cmake)