diff --git a/Dockerfile.apple b/Dockerfile.apple new file mode 100644 index 0000000..7ded966 --- /dev/null +++ b/Dockerfile.apple @@ -0,0 +1,230 @@ +# Dockerfile.apple +# +# Consolidated image for Godot's Apple-platform builds from Linux. +# +# Produces `godot-apple:${img_version}` and is intended to eventually +# replace Dockerfile.osx + Dockerfile.appleembedded once validated. +# For now it exists alongside those images as an experiment. +# +# Supported build outputs: +# * macOS: executable link (editor, templates) via ld64.lld +# * iOS: static libraries (arm64) +# * tvOS: static libraries (arm64) +# * visionOS: static libraries (arm64) +# +# Key simplifications from the existing osx + appleembedded pair: +# +# * No custom Apple-clang build. swiftly's Swift 6.3.x clang is the +# single compiler for C / Obj-C / Obj-C++ / Swift. +# * No custom compiler-rt build. Xcode ships `libclang_rt.{osx,ios, +# tvos,xros,…}.a` inside its toolchain and we link against those. +# * No ioscross / cctools-port wrapper chain. iOS/tvOS/visionOS are +# static-archive builds — they need clang + llvm-ar, no linker — +# so the wrappers are dead weight. +# * darwin-tools-linux-llvm's ld64.lld replaces cctools-port ld for +# macOS linking. Swiftly's bundled lld has Apple platforms disabled +# at build time and cannot be used for Mach-O output. +# +# What's retained from osxcross: cctools-port binutils (lipo, otool, ar) +# for universal-binary assembly and Mach-O introspection. + +ARG img_version +FROM godot-fedora:${img_version} + +ENV XCODE_SDKV=26.5 +ENV APPLE_SDKV=26.5 +ENV SWIFT_VERSION=6.3.2 + +# ----------------------------------------------------------------------------- +# osxcross cctools-port — binutils only (lipo, otool, ar, ranlib, …) +# ----------------------------------------------------------------------------- +# +# We skip `build_apple_clang.sh` (no Apple clang) and `build_compiler_rt.sh` +# (Xcode ships compiler-rt). Just the main `./build.sh` which builds +# libtapi + cctools-port + the `*-apple-darwin25.4-*` wrappers. Built with +# the system (Fedora) clang as CC. +# +# `osxcross-add-sdk-26.patch` adds `darwin25.x` target +# mappings to osxcross's `build.sh` so `SDK_VERSION=26.5 ./build.sh` +# recognizes the SDK. + +RUN dnf -y install --setopt=install_weak_deps=False \ + automake autoconf bzip2-devel clang cmake gawk gcc gcc-c++ libdispatch libicu-devel \ + libtool libxml2-devel openssl-devel uuid-devel yasm gpg && \ + git clone --progress https://github.com/tpoechtrager/osxcross && \ + cd /root/osxcross && \ + # Latest commit from main branch (matches Dockerfile.osx). + git checkout e6ab3fa7423f9235ce9ed6381d6d3af191b46b59 && \ + patch -p1 < /root/files/patches/osxcross-add-sdk-26.patch && \ + ln -s /root/files/MacOSX${APPLE_SDKV}.sdk.tar.xz /root/osxcross/tarballs && \ + UNATTENDED=1 SDK_VERSION=${APPLE_SDKV} ./build.sh && \ + rm -rf /root/osxcross/build + +ENV OSXCROSS_ROOT=/root/osxcross + +# ----------------------------------------------------------------------------- +# Xcode Developer tree (SDKs + Toolchains from Xcode.xip) +# ----------------------------------------------------------------------------- +# +# Provides: +# * Apple SDKs under .../Platforms/{MacOSX,iPhoneOS,AppleTVOS,XROS,…}.platform +# * Swift runtime + stdlib under +# .../Toolchains/XcodeDefault.xctoolchain/usr/lib/swift +# * Compiler-rt under +# .../Toolchains/XcodeDefault.xctoolchain/usr/lib/clang//lib/darwin/ +# (libclang_rt.osx.a, libclang_rt.ios.a, libclang_rt.tvos.a, +# libclang_rt.xros.a, …) + +RUN mkdir -p /root/Xcode.app/Contents/Developer && \ + cd /root/Xcode.app/Contents/Developer && \ + tar xf /root/files/Xcode-Developer${XCODE_SDKV}.tar.xz --strip-components=1 + +# ----------------------------------------------------------------------------- +# Swift toolchain — swiftly +# ----------------------------------------------------------------------------- +# +# Installs to /root/.local/share/swiftly/toolchains/${SWIFT_VERSION}/usr/bin/, +# which provides swift, swiftc, swift-frontend, clang, clang++, +# llvm-ar, llvm-ranlib, llvm-nm, llvm-objdump, llvm-objcopy. +# +# Note: swiftly's bundled `lld` is LLD 21 but was built WITHOUT Apple +# platform support, so it cannot be used to link Mach-O. We use +# darwin-tools-linux-llvm's ld64.lld instead (next step). + +RUN curl -O https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz && \ + tar zxf swiftly-$(uname -m).tar.gz && \ + ./swiftly init --platform ubi9 --quiet-shell-followup --skip-install -y && \ + ~/.local/share/swiftly/bin/swiftly install ${SWIFT_VERSION} && \ + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" && \ + hash -r + +# ----------------------------------------------------------------------------- +# darwin-tools-linux-llvm — Apple-platform-enabled ld64.lld +# ----------------------------------------------------------------------------- +# +# From xtool-org's prebuilt bundle. Provides: +# * ld64.lld — LLD Mach-O driver with macOS/iOS/tvOS/visionOS enabled +# * dsymutil — dSYM generation +# * libtool — llvm-libtool-darwin (Darwin-format static archiver) +# +# Pinned to v1.0.1 (Dec 2024, LLD 20 from swiftlang/llvm-project). +# Known limitation: LLD 20 cannot encode arm64e pauth relocations in +# __cfstring sections, so it can't link arm64e executables. It links +# arm64 (macOS/iOS/tvOS/visionOS) and arm64e static archives fine — +# the archive path doesn't involve lld at all. + +RUN mkdir -p /opt/darwin-tools && \ + curl -fL https://github.com/xtool-org/darwin-tools-linux-llvm/releases/download/v1.0.1/toolset-$(uname -m).tar.gz \ + | tar -xzf - -C /opt/darwin-tools + +# ----------------------------------------------------------------------------- +# PATH +# ----------------------------------------------------------------------------- +# +# Ordering rationale: +# +# 1. /opt/darwin-tools/bin FIRST — clang's `-fuse-ld=lld` looks for +# ld.lld/ld64.lld relative to clang's own bin dir, then PATH. +# Prepending /opt/darwin-tools/bin ensures the Apple-enabled +# ld64.lld wins over swiftly's platform-disabled one. (Clang's +# relative-search would still find swiftly's first; the definitive +# override is `-B /opt/darwin-tools/bin` at link-time, but keeping +# this on PATH helps scripts that invoke ld64.lld directly.) +# +# 2. /root/.local/share/swiftly/bin — so non-login shells (like +# `bash build/build.sh` from scons) find clang/clang++/swift/ +# llvm-ar/llvm-ranlib without sourcing env.sh. +# +# 3. /root/osxcross/target/bin LAST — cctools-port binutils +# (lipo, otool, *-apple-darwin25.4-ar, etc.). +# +# Standard /usr/bin comes after those, so any accidental fallback to +# Fedora's host binutils is unlikely. + +ENV PATH="/opt/darwin-tools/bin:/root/.local/share/swiftly/bin:/root/osxcross/target/bin:${PATH}" + +# ----------------------------------------------------------------------------- +# Swift SDK bundle — for `swift build --swift-sdk darwin-*` workflows. +# ----------------------------------------------------------------------------- +# +# Not strictly required for Godot's scons-driven builds, but enables +# `swift build` cross-compile using the standard SwiftPM Swift SDK +# surface (same mechanism xtool uses). + +RUN /root/files/swift/create-sdk-bundle.sh /root/Xcode.app/Contents/Developer /root/.swiftpm/swift-sdks + +# ----------------------------------------------------------------------------- +# Godot detect.py platform-availability gates +# ----------------------------------------------------------------------------- +# +# platform/{ios,tvos,visionos}/detect.py returns True from can_build() +# when the corresponding OSXCROSS_* env var is set. Value is arbitrary +# (non-empty). OSXCROSS_APPLEEMBEDDED is referenced by the embedded +# drivers for similar gates. + +ENV OSXCROSS_IOS=not_nothing +ENV OSXCROSS_TVOS=not_nothing +ENV OSXCROSS_VISIONOS=not_nothing +ENV OSXCROSS_APPLEEMBEDDED=not_nothing + +# ----------------------------------------------------------------------------- +# ioscross-compatibility shims +# ----------------------------------------------------------------------------- +# +# Godot's platform/{ios,tvos,visionos}/detect.py composes compiler and +# archiver paths as `${APPLE_TOOLCHAIN_PATH}/usr/bin/${apple_target_triple}`. +# The existing build-{ios,tvos,visionos}/build.sh scripts set +# APPLE_TOOLCHAIN_PATH=/root/ioscross/ +# apple_target_triple=-apple-darwin11- +# inherited from the old cctools-port wrapper layout. +# +# This image has no cctools wrappers (iOS/tvOS/visionOS are static-archive +# builds that only need clang + llvm-ar, not a linker). We satisfy the +# path composition with plain symlinks to swiftly's real binaries. When +# clang is invoked as `arm-apple-darwin11-clang` it infers a triple of +# `arm-apple-darwin11`, but scons also passes `-arch arm64` and +# `-mtargetos=`, which override the argv[0]-derived target +# and produce the real arm64-apple-{ios,tvos,xros} triple. +# +# These shims are transitional: they go away once Godot's scons invokes +# clang directly without the APPLE_TOOLCHAIN_PATH composition. + +# Point shims at the real toolchain binaries rather than swiftly's /bin +# entries — those `bin/` entries are symlinks to the `swiftly` dispatcher, +# which reads argv[0] to decide which tool to exec. An argv[0] of +# `arm-apple-darwin11-clang++` isn't a name swiftly recognizes, so it +# falls through to `env arm-apple-darwin11-clang++` and fails. Linking +# to `toolchains/${SWIFT_VERSION}/usr/bin/` bypasses the dispatcher. +RUN for entry in "arm:arm64" "x86_64:x86_64"; do \ + prefix=${entry%:*} ; \ + arch=${entry#*:} ; \ + mkdir -p /root/ioscross/${arch}/bin /root/ioscross/${arch}/usr && \ + ln -s ../bin /root/ioscross/${arch}/usr/bin && \ + for tool in clang clang++ ; do \ + ln -s /root/.local/share/swiftly/toolchains/${SWIFT_VERSION}/usr/bin/${tool} \ + /root/ioscross/${arch}/bin/${prefix}-apple-darwin11-${tool} ; \ + done && \ + ln -s /root/.local/share/swiftly/toolchains/${SWIFT_VERSION}/usr/bin/llvm-ar \ + /root/ioscross/${arch}/bin/${prefix}-apple-darwin11-ar && \ + ln -s /root/.local/share/swiftly/toolchains/${SWIFT_VERSION}/usr/bin/llvm-ranlib \ + /root/ioscross/${arch}/bin/${prefix}-apple-darwin11-ranlib && \ + ln -s /opt/darwin-tools/bin/libtool \ + /root/ioscross/${arch}/bin/${prefix}-apple-darwin11-libtool ; \ + done + +# ----------------------------------------------------------------------------- +# Patch the visionOS SDK for open-source Swift 6.3 compatibility. +# ----------------------------------------------------------------------------- +# +# See files/appleembedded/patch-visionos-sdk.sh for per-category +# rationale and upstream-fix pointers. Applied here rather than in a +# consumer's build script so every run against this image gets a +# consistent SDK state. + +COPY files/appleembedded/patch-visionos-sdk.sh /root/patch-visionos-sdk.sh +RUN chmod +x /root/patch-visionos-sdk.sh && \ + . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" && \ + /root/patch-visionos-sdk.sh && \ + rm /root/patch-visionos-sdk.sh + +CMD /bin/bash diff --git a/Dockerfile.appleembedded b/Dockerfile.appleembedded deleted file mode 100644 index e376195..0000000 --- a/Dockerfile.appleembedded +++ /dev/null @@ -1,40 +0,0 @@ -ARG img_version -FROM godot-osx:${img_version} - -RUN dnf -y install --setopt=install_weak_deps=False \ - automake autoconf gcc gcc-c++ gcc-objc gcc-objc++ cmake libicu-devel libtool libxml2-devel openssl-devel perl python yasm - -RUN git clone --depth 1 --no-checkout https://github.com/tpoechtrager/cctools-port.git && \ - cd /root/cctools-port && \ - git fetch --depth 1 origin 1cce4a06877992f708b2e0e2ab217a0cfb923a4f && \ - git checkout 1cce4a06877992f708b2e0e2ab217a0cfb923a4f - -COPY files/appleembedded/build.sh /root/cctools-port/usage_examples/ios_toolchain/build.sh -COPY files/appleembedded/wrapper.c /root/cctools-port/usage_examples/ios_toolchain/wrapper.c - -RUN chmod +x /root/cctools-port/usage_examples/ios_toolchain/build.sh - -RUN cd /root/cctools-port && \ - usage_examples/ios_toolchain/build.sh arm64 && \ - mkdir -p /root/ioscross/arm64 && \ - mv usage_examples/ios_toolchain/target/* /root/ioscross/arm64 && \ - mkdir /root/ioscross/arm64/usr && \ - ln -s /root/ioscross/arm64/bin /root/ioscross/arm64/usr/bin - -RUN cd /root/cctools-port && \ - usage_examples/ios_toolchain/build.sh x86_64 && \ - mkdir -p /root/ioscross/x86_64 && \ - mv usage_examples/ios_toolchain/target/* /root/ioscross/x86_64 && \ - mkdir /root/ioscross/x86_64/usr && \ - ln -s /root/ioscross/x86_64/bin /root/ioscross/x86_64/usr/bin - -RUN PATH=/root/ioscross/arm64/bin:$PATH /root/files/appleembedded/check-arm.sh - -ENV OSXCROSS_IOS=not_nothing -ENV OSXCROSS_TVOS=not_nothing -ENV OSXCROSS_VISIONOS=not_nothing -ENV OSXCROSS_APPLEEMBEDDED=not_nothing - -ENV PATH="/root/ioscross/arm64/bin:/root/ioscross/x86_64/bin:${PATH}" - -CMD /bin/bash diff --git a/Dockerfile.osx b/Dockerfile.osx deleted file mode 100644 index e35982f..0000000 --- a/Dockerfile.osx +++ /dev/null @@ -1,47 +0,0 @@ -ARG img_version -FROM godot-fedora:${img_version} - -# Additional packages for Swift -# -# sudo dnf install gnupg2 - -ENV XCODE_SDKV=26.1.1 -ENV APPLE_SDKV=26.1 - -RUN dnf -y install --setopt=install_weak_deps=False \ - automake autoconf bzip2-devel cmake gawk gcc gcc-c++ libdispatch libicu-devel libtool \ - libxml2-devel openssl-devel uuid-devel yasm gpg && \ - git clone --progress https://github.com/tpoechtrager/osxcross && \ - cd /root/osxcross && \ - git checkout 121ce150c7857a9474dfff8a8e431482806b3e1b && \ - # Patch to fix visionOS support. - # See: https://github.com/llvm/llvm-project/issues/142502 - patch -p1 < /root/files/patches/osxcross-fix-visionos.patch && \ - ln -s /root/files/MacOSX${APPLE_SDKV}.sdk.tar.xz /root/osxcross/tarballs && \ - export UNATTENDED=1 && \ - export SDK_VERSION=${APPLE_SDKV} && \ - # Custom build Apple Clang to ensure compatibility. - # Find the equivalent LLVM version for the SDK from: - # https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - CLANG_VERSION=19.1.5 ENABLE_CLANG_INSTALL=1 INSTALLPREFIX=/usr ./build_apple_clang.sh && \ - ./build.sh && \ - ./build_compiler_rt.sh && \ - rm -rf /root/osxcross/build - -ENV OSXCROSS_ROOT=/root/osxcross -ENV PATH="/root/osxcross/target/bin:${PATH}" - -# Install Swift 6.2 toolchain - -RUN mkdir -p /root/Xcode.app/Contents/Developer -RUN cd /root/Xcode.app/Contents/Developer && tar xf /root/files/Xcode-Developer${XCODE_SDKV}.tar.xz --strip-components=1 - -RUN curl -O https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz && \ - tar zxf swiftly-$(uname -m).tar.gz && \ - ./swiftly init --platform ubi9 --quiet-shell-followup -y && \ - . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh" && \ - hash -r - -RUN /root/files/swift/create-sdk-bundle.sh /root/Xcode.app/Contents/Developer /root/.swiftpm/swift-sdks - -CMD /bin/bash diff --git a/build.sh b/build.sh index 46ca5ed..8aca5e1 100755 --- a/build.sh +++ b/build.sh @@ -58,8 +58,8 @@ podman_build windows podman_build web podman_build android -XCODE_SDK=26.1.1 -APPLE_SDKV=26.1 +XCODE_SDK=26.4 +APPLE_SDKV=26.4 if [ ! -e "${files_root}"/MacOSX${APPLE_SDKV}.sdk.tar.xz ] || [ ! -e "${files_root}"/Xcode-Developer${XCODE_SDK}.tar.xz ]; then if [ ! -r "${files_root}"/Xcode_${XCODE_SDK}.xip ]; then echo @@ -78,5 +78,4 @@ if [ ! -e "${files_root}"/MacOSX${APPLE_SDKV}.sdk.tar.xz ] || [ ! -e "${files_ro 2>&1 | tee logs/xcode_packer.log fi -podman_build osx -podman_build appleembedded +podman_build apple diff --git a/files/appleembedded/build.sh b/files/appleembedded/build.sh deleted file mode 100755 index cf988ef..0000000 --- a/files/appleembedded/build.sh +++ /dev/null @@ -1,197 +0,0 @@ -#!/usr/bin/env bash - -export LC_ALL=C -pushd "${0%/*}" &>/dev/null - -PLATFORM=$(uname -s) -OPERATING_SYSTEM=$(uname -o || echo "-") - -if [ $OPERATING_SYSTEM == "Android" ]; then - export CC="clang -D__ANDROID_API__=26" - export CXX="clang++ -D__ANDROID_API__=26" -fi - -if [ -z "$LLVM_DSYMUTIL" ]; then - if command -v llvm-dsymutil &>/dev/null; then - LLVM_DSYMUTIL=llvm-dsymutil - else - LLVM_DSYMUTIL=dsymutil - fi -fi - -if [ -z "$JOBS" ]; then - JOBS=$(nproc 2>/dev/null || ncpus 2>/dev/null || echo 1) -fi - -set -e - -function verbose_cmd -{ - echo "$@" - eval "$@" -} - -function git_clone_repository -{ - local url=$1 - local branch=$2 - local directory - - directory=$(basename $url) - directory=${directory/\.git/} - - if [ -n "$CCTOOLS_IOS_DEV" ]; then - rm -rf $directory - cp -r $CCTOOLS_IOS_DEV/$directory . - return - fi - - if [ ! -d $directory ]; then - local args="" - test "$branch" = "master" && args="--depth 1" - git clone $url $args - fi - - pushd $directory &>/dev/null - - git reset --hard - git clean -fdx - git checkout $branch - git pull origin $branch - - popd &>/dev/null -} - - -if [ $# -lt 1 ]; then - echo "usage: $0 " 1>&2 - echo "i.e. $0 arm64" 1>&2 - exit 1 -fi - -TARGET_CPU="$1" -if [ "$TARGET_CPU" != "arm64" ] && [ "$TARGET_CPU" != "x86_64" ]; then - echo "target cpu must be either 'arm64' or 'x86_64'" 1>&2 - exit 1 -fi - -if [ "$TARGET_CPU" == "arm64" ]; then - TRIPLE="arm-apple-darwin11" -else - TRIPLE="x86_64-apple-darwin11" -fi - -TARGETDIR="$PWD/target" - -if [ -d $TARGETDIR ]; then - echo "cleaning up ..." - rm -rf $TARGETDIR -fi - -mkdir -p $TARGETDIR -mkdir -p $TARGETDIR/bin - -echo "" -echo "*** building wrapper ***" -echo "" - -OK=0 - -set +e -version=$(echo "$($LLVM_DSYMUTIL --version 2>&1)" | grep -oP 'LLVM version \K[^\s]+') - -if [ $? -eq 0 ]; then - major_version=$(echo "$version" | awk -F'\\.' '{print $1}') - minor_version=$(echo "$version" | awk -F'\\.' '{print $2}') - if ((major_version > 3 || (major_version == 3 && minor_version >= 8))); then - OK=1 - - if [ "$LLVM_DSYMUTIL" == "llvm-dsymutil" ]; then - ln -sf "$(command -v $LLVM_DSYMUTIL)" "$TARGETDIR/bin/dsymutil" - fi - fi -fi -set -e - -if [ $OK -ne 1 ]; then - echo "int main(){return 0;}" | cc -xc -O2 -o $TARGETDIR/bin/dsymutil - -fi - -pushd $TARGETDIR/bin &>/dev/null -ln -sf $TRIPLE-lipo lipo -popd &>/dev/null - -verbose_cmd cc -O2 -Wall -Wextra -pedantic wrapper.c \ - -DTARGET_CPU=\"\\\"${TARGET_CPU}\\\"\" \ - -o $TARGETDIR/bin/$TRIPLE-clang - -pushd $TARGETDIR/bin &>/dev/null -verbose_cmd ln -sf $TRIPLE-clang $TRIPLE-clang++ -popd &>/dev/null - -rm -rf tmp -mkdir -p tmp - -echo "" -echo "*** building ldid ***" -echo "" - -pushd tmp &>/dev/null -git_clone_repository https://github.com/tpoechtrager/ldid.git master -pushd ldid &>/dev/null -make INSTALLPREFIX=$TARGETDIR -j$JOBS install -popd &>/dev/null -popd &>/dev/null - -echo "" -echo "*** building apple-libdispatch ***" -echo "" - -pushd tmp &>/dev/null -git_clone_repository https://github.com/tpoechtrager/apple-libdispatch.git main -pushd apple-libdispatch &>/dev/null -mkdir -p build -pushd build &>/dev/null -CC=clang CXX=clang++ \ - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=$TARGETDIR -make install -j$JOBS -popd &>/dev/null -popd &>/dev/null -popd &>/dev/null - -echo "" -echo "*** building apple-libtapi ***" -echo "" - -pushd tmp &>/dev/null -git_clone_repository https://github.com/tpoechtrager/apple-libtapi.git 1300.6.5 -pushd apple-libtapi &>/dev/null -INSTALLPREFIX=$TARGETDIR ./build.sh -./install.sh -popd &>/dev/null -popd &>/dev/null - -echo "" -echo "*** building cctools / ld64 ***" -echo "" - -pushd ../../cctools &>/dev/null -git clean -fdx &>/dev/null || true -popd &>/dev/null - -pushd tmp &>/dev/null -mkdir -p cctools -pushd cctools &>/dev/null -../../../../cctools/configure \ - --target=$TRIPLE \ - --prefix=$TARGETDIR \ - --with-libtapi=$TARGETDIR \ - --with-libdispatch=$TARGETDIR \ - --with-libblocksruntime=$TARGETDIR -make -j$JOBS && make install -popd &>/dev/null -popd &>/dev/null - - -echo "" -echo "*** all done ***" diff --git a/files/appleembedded/check-arm.sh b/files/appleembedded/check-arm.sh deleted file mode 100755 index 8ab2233..0000000 --- a/files/appleembedded/check-arm.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -function check_toolchain -{ - local platform=$1 - local sdk_prefix=$2 - # if $3 is true, use the simulator SDK - if [ "$3" == "true" ]; then - SDK_DIR="/root/Xcode.app/Contents/Developer/Platforms/${sdk_prefix}Simulator.platform/Developer/SDKs/${sdk_prefix}Simulator.sdk" - TARGET_OS="${platform}${APPLE_SDKV}-simulator" - NAME="${platform} (Simulator)" - else - SDK_DIR="/root/Xcode.app/Contents/Developer/Platforms/${sdk_prefix}OS.platform/Developer/SDKs/${sdk_prefix}OS.sdk" - TARGET_OS="${platform}${APPLE_SDKV}" - NAME="${platform} (Device)" - fi - - echo "" - echo "*** checking ${NAME} toolchain ***" - echo "" - echo "" - - echo "int main(){return 0;}" | arm-apple-darwin11-clang -isysroot "$SDK_DIR" -mtargetos=${TARGET_OS} -xc -O2 -c -o test.o - || exit 1 - arm-apple-darwin11-ar rcs libtest.a test.o || exit 1 - rm test.o libtest.a - echo "${NAME} toolchain OK" -} - -check_toolchain "ios" "iPhone" false -check_toolchain "tvos" "AppleTV" false -check_toolchain "xros" "XR" false -# Check for simulator toolchains -check_toolchain "ios" "iPhone" true -check_toolchain "tvos" "AppleTV" true -check_toolchain "xros" "XR" true - diff --git a/files/appleembedded/patch-visionos-sdk.sh b/files/appleembedded/patch-visionos-sdk.sh new file mode 100644 index 0000000..f648355 --- /dev/null +++ b/files/appleembedded/patch-visionos-sdk.sh @@ -0,0 +1,245 @@ +#!/bin/bash +# +# Patch Apple's Xcode visionOS SDK so it can be consumed by the open-source +# Swift toolchain from swift.org. Apple's compiler (swiftlang-6.3.0.123.x, +# shipped with Xcode 26) and the swift.org 6.3 release compiler diverge in +# several ways; until the relevant upstream fixes land on `swift/release/6.3` +# and are picked up by a swift.org release, we rewrite the affected header +# and `.swiftinterface` files in place. +# +# This script is idempotent and only touches the visionOS SDK (XROS.sdk). +# +# Remove patches as upstream fixes arrive: +# cat1 - swiftlang/llvm-project#11866 (visionOS availability inference for Obj-C) +# cat2 - no upstream fix yet; the OSS compiler does a strict string compare +# on `// swift-compiler-version:` in .swiftinterface files +# cat3 - Apple private-framework divergences (no upstream fix expected) +# +set -euo pipefail + +SDK="${1:-/root/Xcode.app/Contents/Developer/Platforms/XROS.platform/Developer/SDKs/XROS.sdk}" + +if [ ! -d "$SDK" ]; then + echo "patch-visionos-sdk: SDK not found at $SDK" >&2 + exit 1 +fi + +echo "patch-visionos-sdk: patching $SDK" + +############################################################################### +# cat1: visionOS availability inference for Obj-C headers. +# +# Apple's compiler infers `API_UNAVAILABLE(visionos)` whenever `ios` is in the +# unavailable list (visionOS derives from iOS). The OSS compiler doesn't do +# that inference yet, so we make the implicit explicit by adding `visionos` +# to every `API_UNAVAILABLE(...)` that lists `ios` but not `visionos`. +# +# Upstream fix: swiftlang/llvm-project#11866 (targets swift/release/6.3). +############################################################################### +echo "patch-visionos-sdk: cat1 - adding visionos to API_UNAVAILABLE in headers" +python3 - "$SDK/System/Library/Frameworks" <<'PY' +import os, re, sys +root = sys.argv[1] +pat = re.compile(r"API_UNAVAILABLE\(([^)]*)\)") +def repl(m): + inner = m.group(1) + toks = {t.strip() for t in inner.split(",")} + if "ios" in toks and "visionos" not in toks: + return f"API_UNAVAILABLE({inner}, visionos)" + return m.group(0) +ch_files = ch_calls = 0 +for dp, _, files in os.walk(root): + for fn in files: + if not fn.endswith(".h"): + continue + p = os.path.join(dp, fn) + try: + with open(p, "r", encoding="utf-8") as f: + src = f.read() + except (UnicodeDecodeError, PermissionError): + continue + new, _ = pat.subn(repl, src) + if new != src: + real = sum( + 1 for m in pat.finditer(src) + if "ios" in {t.strip() for t in m.group(1).split(",")} + and "visionos" not in {t.strip() for t in m.group(1).split(",")} + ) + if real: + with open(p, "w", encoding="utf-8") as f: + f.write(new) + ch_files += 1 + ch_calls += real +print(f" patched {ch_calls} calls in {ch_files} files") +PY + +############################################################################### +# cat2: swift-compiler-version stamp in .swiftinterface files. +# +# When the OSS compiler rebuilds a module from its textual interface, it does +# a strict string-compare on the `// swift-compiler-version:` header line. +# Apple's SDK is stamped `swiftlang-6.3.0.123.4` (or .5) and the OSS 6.3 +# release stamps `swift-6.3-RELEASE`, so the check fails. Rewrite the stamp +# to whatever the locally-installed OSS compiler reports. +# +# No upstream fix planned; this is fundamental to how Apple's release +# pipeline diverges from swift.org. +############################################################################### +echo "patch-visionos-sdk: cat2 - rewriting swift-compiler-version stamp in .swiftinterface" +# Try to resolve the OSS compiler's own stamp; fall back to the 6.3 release +# string if swift isn't in PATH at image-build time. +OSS_VERSION="$(swift --version 2>/dev/null | head -1 || true)" +if [ -z "$OSS_VERSION" ]; then + OSS_VERSION="Swift version 6.3 (swift-6.3-RELEASE)" +fi +echo " target stamp: $OSS_VERSION" +OSS_VERSION="$OSS_VERSION" python3 - "$SDK" <<'PY' +import os, re, sys +root = sys.argv[1] +oss = os.environ["OSS_VERSION"] +pat = re.compile(r"^// swift-compiler-version:.*$", re.MULTILINE) +ch = 0 +for dp, _, files in os.walk(root): + for fn in files: + if not fn.endswith(".swiftinterface"): + continue + p = os.path.join(dp, fn) + try: + with open(p, "r", encoding="utf-8") as f: + src = f.read() + except (UnicodeDecodeError, PermissionError): + continue + new, n = pat.subn(f"// swift-compiler-version: {oss}", src) + if n: + try: + with open(p, "w", encoding="utf-8") as f: + f.write(new) + ch += 1 + except PermissionError: + pass +print(f" rewrote stamp in {ch} .swiftinterface files") +PY + +############################################################################### +# cat3a: gut `@inlinable` bodies in RealityFoundation.swiftinterface that +# touch C++-imported types from `simd`/`AVFAudio`. +# +# With `-cxx-interoperability-mode=default` enabled, the OSS compiler treats +# the simd / AVFAudio C headers as C++ and refuses to compile `@inlinable` +# function bodies that use them ("C++ types ... do not support library +# evolution"). The affected declarations are internal helpers that Godot's +# visionOS code never calls, so we replace their bodies with a fatalError +# stub. The framework binary still provides the real implementation at run +# time on actual visionOS hardware. +# +# Gut every `@inlinable internal` unconditionally (they are implementation +# details), and `@inlinable public` only when its body references one of the +# poison tokens. +############################################################################### +RF_IFACE="$SDK/System/Library/Frameworks/RealityFoundation.framework/Modules/RealityFoundation.swiftmodule/arm64e-apple-xros.swiftinterface" +if [ -f "$RF_IFACE" ]; then + echo "patch-visionos-sdk: cat3a - gutting @inlinable bodies in RealityFoundation.swiftinterface" + python3 - "$RF_IFACE" <<'PY' +import sys, re +path = sys.argv[1] +with open(path, "r", encoding="utf-8") as f: + src = f.read() +poison = re.compile( + r"\b(simd_[A-Za-z_0-9]+|columns|AVAudioSourceNodeRenderBlock|AVAudioSinkNodeReceiverBlock)\b|\.vector\b" +) +lines = src.splitlines(keepends=True) +out = [] +i = 0 +gi = gp = 0 + +def find_ob(start): + j = start + while j < len(lines): + if lines[j].rstrip().endswith("{"): + return j, lines[j].rstrip().rfind("{") + j += 1 + return None, None + +def find_cb(ol, oc): + depth = 0 + for li in range(ol, len(lines)): + line = lines[li] + start = oc + 1 if li == ol else 0 + for ci in range(start, len(line)): + ch = line[ci] + if ch == "{": + depth += 1 + elif ch == "}": + if depth == 0: + return li + depth -= 1 + return None + +while i < len(lines): + line = lines[i] + if "@inlinable" in line: + is_internal = "internal" in line + ob, oc = find_ob(i) + if ob is None: + out.append(line); i += 1; continue + cb = find_cb(ob, oc) + if cb is None: + out.append(line); i += 1; continue + body_text = "".join(lines[ob:cb + 1]) + gut = is_internal or bool(poison.search(body_text)) + if gut: + out.extend(lines[i:ob]) + sig_line = lines[ob] + brace_pos = sig_line.rstrip().rfind("{") + out.append(sig_line.rstrip()[:brace_pos + 1] + " Swift.fatalError() }\n") + if is_internal: + gi += 1 + else: + gp += 1 + i = cb + 1 + continue + out.append(line) + i += 1 + +with open(path, "w", encoding="utf-8") as f: + f.write("".join(out)) +print(f" gutted {gi} @inlinable internal + {gp} @inlinable public bodies") +PY + + ########################################################################### + # cat3b: replace a public typealias whose target is an `AVFAudio` C++ block + # type. With C++ interop on, the compiler refuses the typealias itself. + # We swap it to a compatible function type so call sites that use + # `@escaping RealityFoundation.Audio.GeneratorRenderHandler` still parse. + ########################################################################### + echo "patch-visionos-sdk: cat3b - replacing GeneratorRenderHandler typealias in RealityFoundation.swiftinterface" + sed -i \ + "s|public typealias GeneratorRenderHandler = AVFAudio\.AVAudioSourceNodeRenderBlock|public typealias GeneratorRenderHandler = () -> Swift.Void|" \ + "$RF_IFACE" +else + echo "patch-visionos-sdk: cat3a/b - RealityFoundation.swiftinterface not found, skipping" +fi + +############################################################################### +# cat3c: `CTTextAlignment` / `CTLineBreakMode` default values in RealityKit. +# +# Apple's compiler strips the full `kCTTextAlignment` / `kCTLineBreak` prefix +# from these CoreFoundation enums and exposes them as `.left` / +# `.byTruncatingTail`. The OSS compiler strips a shorter prefix (the exact +# Swift name depends on version), so the default-argument expression in +# `MeshResource.generateText(...)` fails to resolve. Replace the defaults +# with raw-value initializers - they're valid regardless of how the compiler +# names the cases. +############################################################################### +RK_IFACE="$SDK/System/Library/Frameworks/RealityKit.framework/Modules/RealityKit.swiftmodule/arm64e-apple-xros.swiftinterface" +if [ -f "$RK_IFACE" ]; then + echo "patch-visionos-sdk: cat3c - replacing CT enum defaults in RealityKit.swiftinterface" + sed -i \ + -e "s|alignment: CoreText\.CTTextAlignment = \.left|alignment: CoreText.CTTextAlignment = CoreText.CTTextAlignment(rawValue: 0)!|g" \ + -e "s|lineBreakMode: CoreText\.CTLineBreakMode = \.byTruncatingTail|lineBreakMode: CoreText.CTLineBreakMode = CoreText.CTLineBreakMode(rawValue: 4)!|g" \ + "$RK_IFACE" +else + echo "patch-visionos-sdk: cat3c - RealityKit.swiftinterface not found, skipping" +fi + +echo "patch-visionos-sdk: done" diff --git a/files/appleembedded/wrapper.c b/files/appleembedded/wrapper.c deleted file mode 100644 index b2ec645..0000000 --- a/files/appleembedded/wrapper.c +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef TARGET_CPU -#define TARGET_CPU "arm64" -#endif - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -#include -#endif - -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -#include -#endif - -#ifdef __OpenBSD__ -#include -#include -#include -#endif - -char *get_executable_path(char *epath, size_t buflen) -{ - char *p; -#ifdef __APPLE__ - unsigned int l = buflen; - if (_NSGetExecutablePath(epath, &l) != 0) return NULL; -#elif defined(__FreeBSD__) || defined(__DragonFly__) - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - size_t l = buflen; - if (sysctl(mib, 4, epath, &l, NULL, 0) != 0) return NULL; -#elif defined(__OpenBSD__) - int mib[4]; - char **argv; - size_t len; - size_t l; - const char *comm; - int ok = 0; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC_ARGS; - mib[2] = getpid(); - mib[3] = KERN_PROC_ARGV; - if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) - abort(); - if (!(argv = malloc(len))) - abort(); - if (sysctl(mib, 4, argv, &len, NULL, 0) < 0) - abort(); - comm = argv[0]; - if (*comm == '/' || *comm == '.') - { - char *rpath; - if ((rpath = realpath(comm, NULL))) - { - strlcpy(epath, rpath, buflen); - free(rpath); - ok = 1; - } - } - else - { - char *sp; - char *xpath = strdup(getenv("PATH")); - char *path = strtok_r(xpath, ":", &sp); - struct stat st; - if (!xpath) - abort(); - while (path) - { - snprintf(epath, buflen, "%s/%s", path, comm); - if (!stat(epath, &st) && (st.st_mode & S_IXUSR)) - { - ok = 1; - break; - } - path = strtok_r(NULL, ":", &sp); - } - free(xpath); - } - free(argv); - if (!ok) return NULL; - l = strlen(epath); -#else - ssize_t l = readlink("/proc/self/exe", epath, buflen - 1); - if (l > 0) epath[l] = '\0'; -#endif - if (l <= 0) return NULL; - epath[buflen - 1] = '\0'; - p = strrchr(epath, '/'); - if (p) *p = '\0'; - return epath; -} - -char *get_filename(char *str) -{ - char *p = strrchr(str, '/'); - return p ? &p[1] : str; -} - -void target_info(char *argv[], char **triple, char **compiler) -{ - char *p = get_filename(argv[0]); - char *x = strrchr(p, '-'); - if (!x) abort(); - *compiler = &x[1]; - *x = '\0'; - *triple = p; -} - -void env(char **p, const char *name, char *fallback) -{ - char *ev = getenv(name); - if (ev) { *p = ev; return; } - *p = fallback; -} - -int main(int argc, char *argv[]) -{ - char **args = alloca(sizeof(char*) * (argc+12)); - int i, j; - - char execpath[PATH_MAX+1]; - - char *compiler; - char *target; - char *cpu = TARGET_CPU; - - target_info(argv, &target, &compiler); - if (!get_executable_path(execpath, sizeof(execpath))) abort(); - - for (i = 1; i < argc; ++i) - { - if (!strcmp(argv[i], "-arch")) - { - cpu = NULL; - break; - } - } - - i = 0; - - args[i++] = compiler; - args[i++] = "-target"; - args[i++] = target; - - if (cpu) - { - args[i++] = "-arch"; - args[i++] = cpu; - } - - args[i++] = "-mlinker-version=955.13"; - args[i++] = "-Wl,-adhoc_codesign"; - args[i++] = "-Wno-unused-command-line-argument"; - - for (j = 1; j < argc; ++i, ++j) - args[i] = argv[j]; - - args[i] = NULL; - - setenv("COMPILER_PATH", execpath, 1); - execvp(compiler, args); - - fprintf(stderr, "cannot invoke compiler!\n"); - return 1; -} diff --git a/files/patches/osxcross-add-sdk-26.patch b/files/patches/osxcross-add-sdk-26.patch new file mode 100644 index 0000000..85bc8c7 --- /dev/null +++ b/files/patches/osxcross-add-sdk-26.patch @@ -0,0 +1,16 @@ + build.sh | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/build.sh b/build.sh +--- a/build.sh (revision e6ab3fa7423f9235ce9ed6381d6d3af191b46b59) ++++ b/build.sh (date 1779656427653) +@@ -68,6 +68,9 @@ + 26|26.0*) TARGET=darwin25; SUPPORTED_ARCHS="arm64 arm64e x86_64 x86_64h"; NEED_TAPI_SUPPORT=1; OSX_VERSION_MIN_INT=10.13 ;; + 26.1*) TARGET=darwin25.1; SUPPORTED_ARCHS="arm64 arm64e x86_64 x86_64h"; NEED_TAPI_SUPPORT=1; OSX_VERSION_MIN_INT=10.13 ;; + 26.2*) TARGET=darwin25.2; SUPPORTED_ARCHS="arm64 arm64e x86_64 x86_64h"; NEED_TAPI_SUPPORT=1; OSX_VERSION_MIN_INT=10.13 ;; ++ 26.3*) TARGET=darwin25.3; SUPPORTED_ARCHS="arm64 arm64e x86_64 x86_64h"; NEED_TAPI_SUPPORT=1; OSX_VERSION_MIN_INT=10.13 ;; ++ 26.4*) TARGET=darwin25.4; SUPPORTED_ARCHS="arm64 arm64e x86_64 x86_64h"; NEED_TAPI_SUPPORT=1; OSX_VERSION_MIN_INT=10.13 ;; ++ 26.5*) TARGET=darwin25.5; SUPPORTED_ARCHS="arm64 arm64e x86_64 x86_64h"; NEED_TAPI_SUPPORT=1; OSX_VERSION_MIN_INT=10.13 ;; + *) echo "Unsupported SDK"; exit 1 ;; + esac + diff --git a/files/patches/osxcross-fix-visionos.patch b/files/patches/osxcross-fix-visionos.patch deleted file mode 100644 index d410fce..0000000 --- a/files/patches/osxcross-fix-visionos.patch +++ /dev/null @@ -1,118 +0,0 @@ -diff --git a/build_clang.sh b/build_clang.sh -index 0d9c36b..57d967e 100755 ---- a/build_clang.sh -+++ b/build_clang.sh -@@ -149,6 +149,15 @@ if [ $GITPROJECT == "apple" ]; then - # lld has been broken by this PR: - # https://github.com/swiftlang/llvm-project/pull/8119 - patch -p1 < $PATCH_DIR/unbreak-apple-lld.patch || true -+ -+ if ([[ $CLANG_VERSION == 19* ]]); then -+ # availability attributes for visionos / xros don't respect being derived from iOS -+ # and this patch fixes that -+ # -+ # https://github.com/swiftlang/llvm-project/issues/10782 -+ patch -p1 < $PATCH_DIR/xros-availability-clang.patch || true -+ fi -+ - popd &>/dev/null - fi - -diff --git a/build_compiler_rt.sh b/build_compiler_rt.sh -index da64909..feb9990 100755 ---- a/build_compiler_rt.sh -+++ b/build_compiler_rt.sh -@@ -98,6 +98,16 @@ fi - get_sources https://github.com/llvm/llvm-project.git $BRANCH "compiler-rt" - - if [ $f_res -eq 1 ]; then -+ if [ $(osxcross-cmp $CLANG_VERSION ">=" 19.0) -eq 1 ]; then -+ pushd "$CURRENT_BUILD_PROJECT_NAME" -+ # availability attributes for visionos / xros don't respect being derived from iOS -+ # and this patch fixes that -+ # -+ # https://github.com/swiftlang/llvm-project/issues/10782 -+ patch -p1 < $PATCH_DIR/xros-availability-clang.patch || true -+ popd -+ fi -+ - pushd "$CURRENT_BUILD_PROJECT_NAME/compiler-rt" &>/dev/null - - if [ $(osxcross-cmp $SDK_VERSION "<=" 10.11) -eq 1 ]; then -diff --git a/patches/xros-availability-clang.patch b/patches/xros-availability-clang.patch -new file mode 100644 -index 0000000..2666a18 ---- /dev/null -+++ b/patches/xros-availability-clang.patch -@@ -0,0 +1,71 @@ -+diff --git a/clang/include/clang/Basic/DarwinSDKInfo.h b/clang/include/clang/Basic/DarwinSDKInfo.h -+index db20b968a..33b36f53c 100644 -+--- a/clang/include/clang/Basic/DarwinSDKInfo.h -++++ b/clang/include/clang/Basic/DarwinSDKInfo.h -+@@ -72,6 +72,13 @@ public: -+ llvm::Triple::TvOS, llvm::Triple::UnknownEnvironment); -+ } -+ -++ /// Returns the os-environment mapping pair that's used to represent the -++ /// iOS -> visionOS version mapping. -++ static inline constexpr OSEnvPair iOStoXROSPair() { -++ return OSEnvPair(llvm::Triple::IOS, llvm::Triple::UnknownEnvironment, -++ llvm::Triple::XROS, llvm::Triple::UnknownEnvironment); -++ } -++ -+ private: -+ StorageType Value; -+ -+diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp -+index e2eada24f..26290b3ba 100644 -+--- a/clang/lib/Sema/SemaDeclAttr.cpp -++++ b/clang/lib/Sema/SemaDeclAttr.cpp -+@@ -2415,6 +2415,48 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { -+ auto NewDeprecated = AdjustTvOSVersion(Deprecated.Version); -+ auto NewObsoleted = AdjustTvOSVersion(Obsoleted.Version); -+ -++ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( -++ ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, -++ NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, -++ Sema::AMK_None, PriorityModifier + Sema::AP_InferredFromOtherPlatform, -++ IIEnvironment); -++ if (NewAttr) -++ D->addAttr(NewAttr); -++ } -++ } else if (S.Context.getTargetInfo().getTriple().isXROS()) { -++ // Transcribe "ios" to "visionos" (and add a new attribute) if the versioning -++ // matches before the start of the visionOS platform. -++ IdentifierInfo *NewII = nullptr; -++ if (II->getName() == "ios") -++ NewII = &S.Context.Idents.get("xros"); -++ else if (II->getName() == "ios_app_extension") -++ NewII = &S.Context.Idents.get("xros_app_extension"); -++ -++ if (NewII) { -++ const auto *SDKInfo = S.getDarwinSDKInfoForAvailabilityChecking(); -++ const auto *IOSToXROSMapping = -++ SDKInfo ? SDKInfo->getVersionMapping( -++ DarwinSDKInfo::OSEnvPair::iOStoXROSPair()) -++ : nullptr; -++ -++ auto AdjustTvOSVersion = -++ [IOSToXROSMapping](VersionTuple Version) -> VersionTuple { -++ if (Version.empty()) -++ return Version; -++ -++ if (IOSToXROSMapping) { -++ if (auto MappedVersion = IOSToXROSMapping->map( -++ Version, VersionTuple(1, 0), std::nullopt)) { -++ return *MappedVersion; -++ } -++ } -++ return Version; -++ }; -++ -++ auto NewIntroduced = AdjustTvOSVersion(Introduced.Version); -++ auto NewDeprecated = AdjustTvOSVersion(Deprecated.Version); -++ auto NewObsoleted = AdjustTvOSVersion(Obsoleted.Version); -++ -+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( -+ ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, -+ NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, diff --git a/upload.sh b/upload.sh index d6a5518..e450523 100755 --- a/upload.sh +++ b/upload.sh @@ -21,5 +21,4 @@ fi "$podman" push godot-xcode:${img_version} ${registry}/godot/xcode "$podman" push godot-android:${img_version} ${registry}/godot-private/android -"$podman" push godot-osx:${img_version} ${registry}/godot-private/macosx -"$podman" push godot-appleembedded:${img_version} ${registry}/godot-private/appleembedded +"$podman" push godot-apple:${img_version} ${registry}/godot-private/apple