Files
UTM/scripts/build_dependencies.sh
T
osy 3c7ee99d06 scripts: stop dependencies weak-linking pipe2() and dup3()
pipe2() and dup3() are new in the 27.0 SDKs and carry
__API_AVAILABLE(macos(27.0), ios(27.0), ...). Both meson's has_function()
and autoconf's AC_CHECK_FUNCS declare their own prototype rather than
including the system header, so they never see that annotation and report
the functions present no matter the deployment target. The real call sites
do include <unistd.h>, so clang emits a weak import that is NULL on
anything older than 27 and the first call branches to zero.

That broke every VM start on iOS 26 and below: -[CSMain init] ->
g_main_context_new() -> g_wakeup_new() -> g_unix_open_pipe(), which calls
pipe2() when glib is configured with HAVE_PIPE2. glib, gio, gettext and
libusb all picked it up in every sysroot built with Xcode 27.

Tell both configure systems the functions are missing so the existing
pipe() + fcntl(FD_CLOEXEC) fallbacks are compiled in instead. Nothing
detects dup3() today, but cover it so the next dependency bump cannot
reintroduce the same crash.

Assisted-by: Claude:claude-opus-5
2026-09-20 15:12:05 -05:00

1260 lines
42 KiB
Bash
Executable File

#!/bin/sh
# Based off of https://github.com/szanni/ios-autotools/blob/master/iconfigure
# Copyright (c) 2014, Angelo Haller
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
set -e
# Printing coloured lines
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
# Knobs
IOS_SDKMINVER="15.0"
MAC_SDKMINVER="12.0"
VISIONOS_SDKMINVER="1.0"
# Network operations are retried because concurrent builds on the same CI runner
# get rate limited by GitHub and fail to clone/fetch.
RETRY_ATTEMPTS="${RETRY_ATTEMPTS:-5}"
RETRY_DELAY="${RETRY_DELAY:-15}"
# Build environment
PLATFORM=
CHOST=
SDK=
SDKMINVER=
CLEAN_PATH="$PATH"
DEBUG=
command -v realpath >/dev/null 2>&1 || realpath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
version_check() {
[ "$1" = "$(echo "$1\n$2" | sort -V | head -n1)" ]
}
usage () {
echo "Usage: [VARIABLE...] $(basename $0) [-p platform] [-a architecture] [-q qemu_path] [-d] [-r] [-x]"
echo ""
echo " -p platform Target platform. Default ios. [ios|ios_simulator|ios-tci|ios_simulator-tci|macos|visionos|visionos_simulator]"
echo " -a architecture Target architecture. Default arm64. [armv7|armv7s|arm64|i386|x86_64]"
echo " -q qemu_path Do not download QEMU, use qemu_path instead."
echo " -d, --download Force re-download of source even if already downloaded."
echo " -r, --rebuild Avoid cleaning build directory."
echo " -x, --debug Build for debug."
echo ""
echo " VARIABLEs are:"
echo " NCPU Number of CPUs to use in 'make', 0 to use all cores."
echo " SDKVERSION Target a specific SDK version."
echo " CHOST Configure host, set if not deducable by ARCH."
echo ""
echo " CFLAGS CPPFLAGS CXXFLAGS LDFLAGS"
echo ""
exit 1
}
python_module_test () {
python3 -c "import $1"
}
check_env () {
command -v brew >/dev/null 2>&1 || { echo >&2 "${RED}Homebrew is required to be installed.${NC}"; exit 1; }
brew --prefix llvm >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'llvm' from Homebrew.${NC}"; exit 1; }
brew --prefix spirv-llvm-translator >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'spirv-llvm-translator' from Homebrew.${NC}"; exit 1; }
brew --prefix libxcb >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'libxcb' from Homebrew.${NC}"; exit 1; }
brew --prefix libxrandr >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'libxrandr' from Homebrew.${NC}"; exit 1; }
command -v python3 >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'python3' on your host machine.${NC}"; exit 1; }
python_module_test six >/dev/null 2>&1 || { echo >&2 "${RED}'six' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test pyparsing >/dev/null 2>&1 || { echo >&2 "${RED}'pyparsing' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test distutils >/dev/null 2>&1 || { echo >&2 "${RED}'setuptools' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test yaml >/dev/null 2>&1 || { echo >&2 "${RED}'pyyaml' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test distlib >/dev/null 2>&1 || { echo >&2 "${RED}'distlib' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test mako >/dev/null 2>&1 || { echo >&2 "${RED}'mako' not found in your Python 3 installation.${NC}"; exit 1; }
command -v meson >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'meson' on your host machine.${NC}"; exit 1; }
command -v cmake >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'cmake' on your host machine.${NC}"; exit 1; }
command -v msgfmt >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'gettext' on your host machine.\n\t'msgfmt' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v glib-mkenums >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'glib-utils' on your host machine.\n\t'glib-mkenums' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v glib-compile-resources >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'glib-utils' on your host machine.\n\t'glib-compile-resources' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v gpg-error-config >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'libgpg-error' on your host machine.\n\t'gpg-error-config' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v xcrun >/dev/null 2>&1 || { echo >&2 "${RED}'xcrun' is not found. Make sure you are running on OSX."; exit 1; }
command -v otool >/dev/null 2>&1 || { echo >&2 "${RED}'otool' is not found. Make sure you are running on OSX."; exit 1; }
command -v install_name_tool >/dev/null 2>&1 || { echo >&2 "${RED}'install_name_tool' is not found. Make sure you are running on OSX."; exit 1; }
version_check "2.4" "$(bison -V | head -1 | awk '{ print $NF }')" || { echo >&2 "${RED}'bison' >= 2.4 is required. Did you install from Homebrew and updated your \$PATH variable?"; exit 1; }
}
# Run a command, retrying with exponential backoff if it fails. Jitter is derived
# from the PID so that concurrent builds do not retry in lockstep.
retry () {
ATTEMPT=1
DELAY="$RETRY_DELAY"
while true; do
"$@" && return 0
STATUS=$?
if [ $ATTEMPT -ge $RETRY_ATTEMPTS ]; then
echo >&2 "${RED}'$*' failed after $ATTEMPT attempts.${NC}"
return $STATUS
fi
SLEEP=$(( DELAY + ($$ + ATTEMPT) % 10 ))
echo >&2 "${RED}'$*' failed (attempt $ATTEMPT of $RETRY_ATTEMPTS), retrying in ${SLEEP}s...${NC}"
sleep $SLEEP
ATTEMPT=$(( ATTEMPT + 1 ))
DELAY=$(( DELAY * 2 ))
done
}
download () {
URL=$1
FILE="$(basename $URL)"
NAME="${FILE%.tar.*}"
TARGET="$BUILD_DIR/$FILE"
DIR="$BUILD_DIR/$NAME"
PATCH="$PATCHES_DIR/${NAME}.patch"
DATA="$PATCHES_DIR/data/${NAME}"
if [ -f "$TARGET" -a -z "$REDOWNLOAD" ]; then
echo "${GREEN}$TARGET already downloaded! Run with -d to force re-download.${NC}"
else
echo "${GREEN}Downloading ${URL}${NC}"
retry curl -f -L -O "$URL"
mv "$FILE" "$TARGET"
fi
if [ -d "$DIR" ]; then
echo "${GREEN}Deleting existing build directory ${DIR}...${NC}"
rm -rf "$DIR"
fi
echo "${GREEN}Unpacking ${NAME}...${NC}"
tar -xf "$TARGET" -C "$BUILD_DIR"
if [ -f "$PATCH" ]; then
echo "${GREEN}Patching ${NAME}...${NC}"
patch -d "$DIR" -p1 < "$PATCH"
fi
if [ -d "$DATA" ]; then
echo "${GREEN}Patching data ${NAME}...${NC}"
cp -r "$DATA/" "$DIR"
fi
}
# Discard any partial clone from a previous attempt so that a retry starts clean.
clone_fresh () {
rm -rf "$2"
git clone --filter=tree:0 --no-checkout "$1" "$2"
}
clone () {
REPO="$1"
COMMIT="$2"
SUBDIRS="$3"
NAME="$(basename $REPO)"
DIR="$BUILD_DIR/$NAME"
if [ -d "$DIR" -a -z "$REDOWNLOAD" ]; then
echo "${GREEN}$DIR already downloaded! Run with -d to force re-download.${NC}"
else
echo "${GREEN}Cloning ${REPO}...${NC}"
retry clone_fresh "$REPO" "$DIR"
if [ ! -z "$SUBDIRS" ]; then
git -C "$DIR" sparse-checkout init
git -C "$DIR" sparse-checkout set $SUBDIRS
fi
fi
# tree:0 filtered clones fetch missing objects here, so these hit the network too
retry git -C "$DIR" checkout "$COMMIT"
retry git -C "$DIR" submodule update --init --recursive --filter=tree:0
}
clone_moltenvk_dependences () {
REPO="$1"
NAME="$(basename $REPO)"
DIR="$BUILD_DIR/$NAME"
pwd="$(pwd)"
cd "$DIR"
retry "./fetchDependencies" --none -v
cd "$pwd"
}
download_all () {
[ -d "$BUILD_DIR" ] || mkdir -p "$BUILD_DIR"
download $PKG_CONFIG_SRC
download $FFI_SRC
download $ICONV_SRC
download $GETTEXT_SRC
download $PNG_SRC
download $JPEG_TURBO_SRC
download $GLIB_SRC
download $GPG_ERROR_SRC
download $GCRYPT_SRC
download $PIXMAN_SRC
download $OPENSSL_SRC
download $TPMS_SRC
download $SWTPM_SRC
download $OPUS_SRC
download $SPICE_PROTOCOL_SRC
download $SPICE_SERVER_SRC
download $JSON_GLIB_SRC
download $GST_SRC
download $GST_BASE_SRC
download $GST_GOOD_SRC
download $XML2_SRC
download $SOUP_SRC
download $PHODAV_SRC
download $SPICE_CLIENT_SRC
download $ZSTD_SRC
download $SLIRP_SRC
download $QEMU_SRC
if [ -z "$SKIP_USB_BUILD" ]; then
download $USB_SRC
download $USBREDIR_SRC
fi
clone $WEBKIT_REPO $WEBKIT_COMMIT "$WEBKIT_SUBDIRS"
clone $EPOXY_REPO $EPOXY_COMMIT
clone $VULKAN_LOADER_REPO $VULKAN_LOADER_COMMIT
clone $VIRGLRENDERER_REPO $VIRGLRENDERER_COMMIT
clone $HYPERVISOR_REPO $HYPERVISOR_COMMIT
clone $LIBUCONTEXT_REPO $LIBUCONTEXT_COMMIT
clone $MESA_REPO $MESA_COMMIT
clone $MOLTENVK_REPO $MOLTENVK_COMMIT
clone_moltenvk_dependences $MOLTENVK_REPO
download $LLVM15_SRC
clone $DXMT_REPO $DXMT_COMMIT
clone $D3DMETAL_REPO $D3DMETAL_COMMIT
}
copy_private_headers() {
if [ "$PLATFORM" == "macos" ]; then
# already in the SDK and a second copy conflicts with the IOKit module
return
fi
MACOS_SDK_PATH="$(xcrun --sdk macosx --show-sdk-path)"
IOKIT_HEADERS_PATH="$MACOS_SDK_PATH/System/Library/Frameworks/IOKit.framework/Headers"
OSTYPES_HEADERS_PATH="$MACOS_SDK_PATH/usr/include/libkern"
OUTPUT_INCLUDES="$PREFIX/include"
if [ ! -d "$IOKIT_HEADERS_PATH" ]; then
echo "${RED}Failed to find IOKit headers in: $IOKIT_HEADERS_PATH${NC}"
exit 1
fi
if [ ! -d "$OSTYPES_HEADERS_PATH" ]; then
echo "${RED}Failed to find libkern headers in: $OSTYPES_HEADERS_PATH${NC}"
exit 1
fi
echo "${GREEN}Copying private headers...${NC}"
mkdir -p "$OUTPUT_INCLUDES"
cp -r "$IOKIT_HEADERS_PATH" "$OUTPUT_INCLUDES/IOKit"
rm "$OUTPUT_INCLUDES/IOKit/storage/IOMedia.h" # needed to pass QEMU check
# patch headers
LC_ALL=C sed -i '' -e 's/#if KERNEL_USER32/#if 0/g' $(find "$OUTPUT_INCLUDES/IOKit" -type f)
LC_ALL=C sed -i '' -e 's/#if !KERNEL_USER32/#if 1/g' $(find "$OUTPUT_INCLUDES/IOKit" -type f)
LC_ALL=C sed -i '' -e 's/#if KERNEL/#if 0/g' $(find "$OUTPUT_INCLUDES/IOKit" -type f)
LC_ALL=C sed -i '' -e 's/#if !KERNEL/#if 1/g' $(find "$OUTPUT_INCLUDES/IOKit" -type f)
LC_ALL=C sed -i '' -e 's/__UNAVAILABLE_PUBLIC_IOS;/;/g' $(find "$OUTPUT_INCLUDES/IOKit" -type f)
mkdir -p "$OUTPUT_INCLUDES/libkern"
cp -r "$OSTYPES_HEADERS_PATH/OSTypes.h" "$OUTPUT_INCLUDES/libkern/OSTypes.h"
}
meson_quote() {
echo "'$(echo $* | sed "s/ /','/g")'"
}
generate_meson_cross() {
cross="$1"
system="$2"
echo "# Automatically generated - do not modify" > $cross
echo "[properties]" >> $cross
echo "needs_exe_wrapper = true" >> $cross
# pipe2() and dup3() are new in the 27.0 SDKs. Meson's has_function() check declares
# its own prototype, so it never sees the availability attribute and reports them
# present no matter the deployment target. The real call sites do include the system
# header, which leaves a weak import that is NULL when running on an older OS.
echo "has_function_pipe2 = false" >> $cross
echo "has_function_dup3 = false" >> $cross
echo "[built-in options]" >> $cross
echo "c_args = [${CFLAGS:+$(meson_quote $CFLAGS)}]" >> $cross
echo "cpp_args = [${CXXFLAGS:+$(meson_quote $CXXFLAGS)}]" >> $cross
echo "objc_args = [${OBJCFLAGS:+$(meson_quote $OBJCFLAGS)}]" >> $cross
echo "objcpp_args = [${OBJCFLAGS:+$(meson_quote $OBJCFLAGS)}]" >> $cross
echo "c_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
echo "cpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
echo "objc_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
echo "objcpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
echo "[binaries]" >> $cross
echo "c = [$(meson_quote $CC)]" >> $cross
echo "cpp = [$(meson_quote $CXX)]" >> $cross
echo "objc = [$(meson_quote $OBJCC)]" >> $cross
echo "objcpp = [$(meson_quote $OBJCC)]" >> $cross
echo "ar = [$(meson_quote $AR)]" >> $cross
echo "nm = [$(meson_quote $NM)]" >> $cross
echo "pkgconfig = ['$PREFIX/host/bin/pkg-config']" >> $cross
echo "ranlib = [$(meson_quote $RANLIB)]" >> $cross
echo "strip = [$(meson_quote $STRIP), '-x']" >> $cross
echo "python = ['$(which python3)']" >> $cross
echo "glib-mkenums = ['$(which glib-mkenums)']" >> $cross
echo "glib-compile-resources = ['$(which glib-compile-resources)']" >> $cross
echo "[host_machine]" >> $cross
if [ "$system" == "auto" ]; then
case $PLATFORM in
ios* | visionos* )
echo "system = 'ios'" >> $cross
;;
macos )
echo "system = 'darwin'" >> $cross
;;
esac
else
echo "system = '$system'" >> $cross
fi
if [ "$system" == "darwin" ]; then
echo "kernel = 'xnu'" >> $cross
case $PLATFORM in
ios_simulator* )
echo "subsystem = 'ios-simulator'" >> $cross
;;
ios* )
echo "subsystem = 'ios'" >> $cross
;;
visionos_simulator* )
echo "subsystem = 'visionos-simulator'" >> $cross
;;
visionos* )
echo "subsystem = 'visionos'" >> $cross
;;
macos )
echo "subsystem = 'macos'" >> $cross
;;
esac
fi
case "$ARCH" in
armv7 | armv7s )
echo "cpu_family = 'arm'" >> $cross
;;
arm64 )
echo "cpu_family = 'aarch64'" >> $cross
;;
i386 )
echo "cpu_family = 'x86'" >> $cross
;;
x86_64 )
echo "cpu_family = 'x86_64'" >> $cross
;;
*)
echo "cpu_family = '$ARCH'" >> $cross
;;
esac
echo "cpu = '$ARCH'" >> $cross
echo "endian = 'little'" >> $cross
}
generate_cmake_toolchain() {
toolchain="$1"
# Extract compiler executables
CC_BIN="${CC%% *}"
CXX_BIN="${CXX%% *}"
OBJC_BIN="${OBJCC%% *}"
echo "# Automatically generated - do not modify" > "$toolchain"
echo "" >> "$toolchain"
echo "cmake_minimum_required(VERSION 3.28)" >> "$toolchain"
echo "" >> "$toolchain"
#
# Target platform
#
case $PLATFORM in
ios_simulator* )
echo "set(CMAKE_SYSTEM_NAME iOS)" >> "$toolchain"
echo "set(CMAKE_OSX_SYSROOT iphonesimulator CACHE STRING \"\" FORCE)" >> "$toolchain"
;;
ios* )
echo "set(CMAKE_SYSTEM_NAME iOS)" >> "$toolchain"
echo "set(CMAKE_OSX_SYSROOT iphoneos CACHE STRING \"\" FORCE)" >> "$toolchain"
;;
visionos_simulator* )
echo "set(CMAKE_SYSTEM_NAME visionOS)" >> "$toolchain"
echo "set(CMAKE_OSX_SYSROOT xrsimulator CACHE STRING \"\" FORCE)" >> "$toolchain"
;;
visionos* )
echo "set(CMAKE_SYSTEM_NAME visionOS)" >> "$toolchain"
echo "set(CMAKE_OSX_SYSROOT xros CACHE STRING \"\" FORCE)" >> "$toolchain"
;;
macos )
echo "set(CMAKE_SYSTEM_NAME Darwin)" >> "$toolchain"
;;
esac
echo "" >> "$toolchain"
#
# Architecture
#
echo "set(CMAKE_SYSTEM_PROCESSOR \"$ARCH\")" >> "$toolchain"
echo "set(CMAKE_OSX_ARCHITECTURES \"$ARCH\" CACHE STRING \"\" FORCE)" >> "$toolchain"
echo "set(CMAKE_MACOSX_BUNDLE OFF CACHE BOOL \"\")" >> "$toolchain"
echo "" >> "$toolchain"
#
# Deployment target (derive from -m* flags if present, otherwise leave unset)
#
case "$PLATFORM" in
ios* )
echo "set(CMAKE_OSX_DEPLOYMENT_TARGET \"$IOS_SDKMINVER\")" >> "$toolchain"
;;
visionos* )
echo "set(CMAKE_OSX_DEPLOYMENT_TARGET \"$VISIONOS_SDKMINVER\")" >> "$toolchain"
;;
macos )
echo "set(CMAKE_OSX_DEPLOYMENT_TARGET \"$MAC_SDKMINVER\")" >> "$toolchain"
;;
esac
echo "" >> "$toolchain"
#
# Compilers
#
echo "set(CMAKE_C_COMPILER \"$CC_BIN\")" >> "$toolchain"
echo "set(CMAKE_CXX_COMPILER \"$CXX_BIN\")" >> "$toolchain"
echo "set(CMAKE_OBJC_COMPILER \"$OBJC_BIN\")" >> "$toolchain"
echo "set(CMAKE_ASM_COMPILER \"$CC_BIN\")" >> "$toolchain"
echo "" >> "$toolchain"
#
# Binutils
#
echo "set(CMAKE_AR \"$AR\")" >> "$toolchain"
echo "set(CMAKE_NM \"$NM\")" >> "$toolchain"
echo "set(CMAKE_RANLIB \"$RANLIB\")" >> "$toolchain"
echo "set(CMAKE_STRIP \"$STRIP\")" >> "$toolchain"
echo "" >> "$toolchain"
#
# Flags
#
if [ -n "$CFLAGS" ]; then
echo "set(CMAKE_C_FLAGS \"$CFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
echo "set(CMAKE_ASM_FLAGS \"$CFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
fi
if [ -n "$OBJCFLAGS" ]; then
echo "set(CMAKE_OBJC_FLAGS \"$OBJCFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
fi
if [ -n "$CXXFLAGS" ]; then
echo "set(CMAKE_CXX_FLAGS \"$CXXFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
fi
if [ -n "$LDFLAGS" ]; then
echo "set(CMAKE_EXE_LINKER_FLAGS \"$LDFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
echo "set(CMAKE_SHARED_LINKER_FLAGS \"$LDFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
echo "set(CMAKE_MODULE_LINKER_FLAGS \"$LDFLAGS\" CACHE STRING \"\" FORCE)" >> "$toolchain"
fi
echo "" >> "$toolchain"
#
# pkg-config (critical for Apple cross builds)
#
echo "set(ENV{PKG_CONFIG} \"$PREFIX/host/bin/pkg-config\")" >> "$toolchain"
echo "set(ENV{PKG_CONFIG_SYSROOT_DIR} \"$PREFIX\")" >> "$toolchain"
echo "set(ENV{PKG_CONFIG_PATH} \"$PREFIX/host/lib/pkgconfig:$PREFIX/host/share/pkgconfig\")" >> "$toolchain"
echo "" >> "$toolchain"
#
# Python (for find_package(Python3))
#
echo "set(Python3_EXECUTABLE \"$(which python3)\")" >> "$toolchain"
echo "" >> "$toolchain"
#
# Cross-compile search behavior
#
echo "set(CMAKE_FIND_ROOT_PATH \"$PREFIX\")" >> "$toolchain"
echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> "$toolchain"
echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)" >> "$toolchain"
echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> "$toolchain"
echo "set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)" >> "$toolchain"
}
# Prevent contamination from host pkg-config files by building our own
build_pkg_config() {
FILE="$(basename $PKG_CONFIG_SRC)"
NAME="${FILE%.tar.*}"
DIR="$BUILD_DIR/$NAME"
pwd="$(pwd)"
cd "$DIR"
if [ -z "$REBUILD" ]; then
echo "${GREEN}Configuring ${NAME}...${NC}"
env -i CFLAGS="-Wno-error=int-conversion" ./configure --prefix="$PREFIX" --bindir="$PREFIX/host/bin" --with-internal-glib $@
fi
echo "${GREEN}Building ${NAME}...${NC}"
make -j$NCPU
echo "${GREEN}Installing ${NAME}...${NC}"
make install
cd "$pwd"
export PATH="$PREFIX/host/bin:$PATH"
export PKG_CONFIG="$PREFIX/host/bin/pkg-config"
}
build_openssl() {
URL=$1
shift 1
FILE="$(basename $URL)"
NAME="${FILE%.tar.*}"
DIR="$BUILD_DIR/$NAME"
pwd="$(pwd)"
TOOLCHAIN_PATH="$(dirname $(xcrun --sdk $SDK -find clang))"
PATH="$PATH:$TOOLCHAIN_PATH"
CROSS_TOP="$(xcrun --sdk $SDK --show-sdk-platform-path)/Developer" # for openssl
CROSS_SDK="$SDKNAME$SDKVERSION.sdk" # for openssl
export CROSS_TOP
export CROSS_SDK
export PATH
case $ARCH in
armv7 | armv7s )
OPENSSL_CROSS=iphoneos-cross
;;
arm64 )
OPENSSL_CROSS=ios64-cross
;;
i386 )
OPENSSL_CROSS=darwin-i386-cc
;;
x86_64 )
OPENSSL_CROSS=darwin64-x86_64-cc
;;
esac
case $PLATFORM in
ios | ios-tci )
case $ARCH in
armv7 | armv7s )
OPENSSL_CROSS=iphoneos-cross
;;
arm64 )
OPENSSL_CROSS=ios64-cross
;;
i386 | x86_64 )
OPENSSL_CROSS=iossimulator64-cross
;;
esac
;;
macos )
case $ARCH in
arm64 )
OPENSSL_CROSS=darwin64-arm64-cc
;;
i386 )
OPENSSL_CROSS=darwin-i386-cc
;;
x86_64 )
OPENSSL_CROSS=darwin64-x86_64-cc
;;
esac
;;
visionos_simulator )
OPENSSL_CROSS=visionos-sim-cross-$ARCH
;;
visionos* )
OPENSSL_CROSS=visionos-cross-$ARCH
;;
esac
if [ -z "$OPENSSL_CROSS" ]; then
echo "${RED}Unsupported configuration for OpenSSL $PLATFORM, $ARCH${NC}"
exit 1
fi
if [ ! -z "$DEBUG" ]; then
DEBUG_FLAGS="--debug"
fi
cd "$DIR"
if [ -z "$REBUILD" ]; then
echo "${GREEN}Configuring ${NAME}...${NC}"
./Configure $OPENSSL_CROSS no-dso no-hw no-engine --prefix="$PREFIX" $DEBUG_FLAGS $@
fi
echo "${GREEN}Building ${NAME}...${NC}"
make -j$NCPU
echo "${GREEN}Installing ${NAME}...${NC}"
make install
cd "$pwd"
}
build () {
if [ -d "$1" ]; then
DIR="$1"
NAME="$(basename "$DIR")"
else
URL=$1
shift 1
FILE="$(basename $URL)"
NAME="${FILE%.tar.*}"
DIR="$BUILD_DIR/$NAME"
fi
pwd="$(pwd)"
cd "$DIR"
if [ -z "$REBUILD" ]; then
echo "${GREEN}Configuring ${NAME}...${NC}"
./configure --prefix="$PREFIX" --host="$CHOST" $@
fi
echo "${GREEN}Building ${NAME}...${NC}"
make -j$NCPU
echo "${GREEN}Installing ${NAME}...${NC}"
make install
cd "$pwd"
}
meson_cross_build () {
CROSS="$1"
SRCDIR="$2"
shift 2
FILE="$(basename $SRCDIR)"
NAME="${FILE%.tar.*}"
case $SRCDIR in
http* | ftp* )
SRCDIR="$BUILD_DIR/$NAME"
;;
esac
MESON_CROSS="$(realpath "$BUILD_DIR")/meson-$CROSS$MESON_CROSS_SUFFIX.cross"
if [ ! -f "$MESON_CROSS" ]; then
generate_meson_cross "$MESON_CROSS" "$CROSS"
fi
pwd="$(pwd)"
if [ -z "$DEBUG" ]; then
buildtype="release"
else
buildtype="debug"
fi
cd "$SRCDIR"
if [ -z "$REBUILD" ]; then
rm -rf utm_build
echo "${GREEN}Configuring ${NAME}...${NC}"
meson utm_build --prefix="$PREFIX" --buildtype="$buildtype" --cross-file "$MESON_CROSS" "$@"
fi
echo "${GREEN}Building ${NAME}...${NC}"
meson compile -C utm_build -j $NCPU
echo "${GREEN}Installing ${NAME}...${NC}"
meson install -C utm_build
cd "$pwd"
}
meson_build () {
meson_cross_build auto $@
}
meson_darwin_build () {
meson_cross_build darwin $@
}
# The generated toolchain file is the single source of truth for CMake builds:
# it sets every compiler, binutil, and flag variable with CACHE FORCE. The
# exported CC/CFLAGS/... are needed by the autotools and meson builds, but for
# CMake they are redundant *and* harmful: a nested host configure that does not
# get the toolchain file (such as LLVM's NATIVE sub-build for llvm-tblgen)
# inherits them from the environment and ends up compiling for the target while
# discovering and linking host libraries. Drop them for every cmake invocation.
cmake_clean_env () {
env -u CC -u CPP -u CXX -u OBJCC -u LD -u AR -u NM -u RANLIB -u STRIP \
-u CFLAGS -u CPPFLAGS -u CXXFLAGS -u OBJCFLAGS -u LDFLAGS \
cmake "$@"
}
cmake_build () {
SRCDIR="$1"
shift 1
FILE="$(basename $SRCDIR)"
NAME="${FILE%.tar.*}"
BUILDDIR="utm_build"
case $SRCDIR in
http* | ftp* )
SRCDIR="$BUILD_DIR/$NAME"
;;
esac
CMAKE_TOOLCHAIN="$(realpath "$BUILD_DIR")/cross.cmake"
if [ ! -f "$CMAKE_TOOLCHAIN" ]; then
generate_cmake_toolchain "$CMAKE_TOOLCHAIN"
fi
pwd="$(pwd)"
cd "$SRCDIR"
if [ -z "$REBUILD" ]; then
rm -rf "$BUILDDIR"
mkdir -p "$BUILDDIR"
echo "${GREEN}Configuring ${NAME}...${NC}"
cmake_clean_env -S . -B "$BUILDDIR" \
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-DCMAKE_BUILD_TYPE="$BUILD_CONFIGURATION" \
-DCMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN" \
"$@"
fi
echo "${GREEN}Building ${NAME}...${NC}"
cmake_clean_env --build "$BUILDDIR" --parallel "$NCPU"
echo "${GREEN}Installing ${NAME}...${NC}"
cmake_clean_env --install "$BUILDDIR"
cd "$pwd"
}
build_angle () {
OLD_PATH=$PATH
export PATH="$(realpath "$BUILD_DIR/depot_tools.git"):$OLD_PATH"
pwd="$(pwd)"
cd "$BUILD_DIR/WebKit.git/Source/ThirdParty/ANGLE"
env -i PATH=$PATH xcodebuild archive -archivePath "ANGLE" \
-scheme "ANGLE" \
-sdk $SDK \
-arch $ARCH \
-configuration "$BUILD_CONFIGURATION" \
WEBCORE_LIBRARY_DIR="/usr/local/lib" \
NORMAL_UMBRELLA_FRAMEWORKS_DIR="" \
CODE_SIGNING_ALLOWED=NO \
GCC_TREAT_WARNINGS_AS_ERRORS=NO \
IPHONEOS_DEPLOYMENT_TARGET="$IOS_SDKMINVER" \
MACOSX_DEPLOYMENT_TARGET="$MAC_SDKMINVER" \
XROS_DEPLOYMENT_TARGET="$VISIONOS_SDKMINVER"
rsync -a "ANGLE.xcarchive/Products/usr/local/lib/" "$PREFIX/lib"
rsync -a "include/" "$PREFIX/include"
cd "$pwd"
export PATH=$OLD_PATH
}
build_hypervisor () {
OLD_PATH=$PATH
export PATH="$(realpath "$BUILD_DIR/depot_tools.git"):$OLD_PATH"
pwd="$(pwd)"
cd "$BUILD_DIR/Hypervisor.git"
case $PLATFORM in
*simulator* )
scheme="HypervisorSimulator"
;;
* )
scheme="Hypervisor"
;;
esac
echo "${GREEN}Building Hypervisor...${NC}"
env -i PATH=$PATH xcodebuild archive -archivePath "Hypervisor" -scheme "$scheme" -sdk $SDK -configuration "$BUILD_CONFIGURATION" \
IPHONEOS_DEPLOYMENT_TARGET="$IOS_SDKMINVER" \
MACOSX_DEPLOYMENT_TARGET="$MAC_SDKMINVER" \
XROS_DEPLOYMENT_TARGET="$VISIONOS_SDKMINVER"
rsync -a "Hypervisor.xcarchive/Products/Library/Frameworks/" "$PREFIX/Frameworks"
cd "$pwd"
export PATH=$OLD_PATH
}
build_qemu_dependencies () {
build $FFI_SRC
build $ICONV_SRC
gl_cv_onwards_func_strchrnul=future build $GETTEXT_SRC --disable-java
build $PNG_SRC
build $JPEG_TURBO_SRC
meson_build $GLIB_SRC -Dtests=false -Ddtrace=disabled
build $GPG_ERROR_SRC
build $GCRYPT_SRC
build $PIXMAN_SRC
build_openssl $OPENSSL_SRC
build $TPMS_SRC --disable-shared
build $SWTPM_SRC --enable-shared-lib
build $OPUS_SRC
ZSTD_BASENAME="$(basename $ZSTD_SRC)"
meson_build "$BUILD_DIR/${ZSTD_BASENAME%.tar.*}/build/meson"
meson_build $GST_SRC -Dtests=disabled -Ddefault_library=both -Dregistry=false
meson_build $GST_BASE_SRC -Dtests=disabled -Ddefault_library=both -Dgl=disabled
meson_build $GST_GOOD_SRC -Dtests=disabled -Ddefault_library=both
meson_build $SPICE_PROTOCOL_SRC
meson_build $SPICE_SERVER_SRC -Dlz4=false -Dsasl=false
meson_darwin_build $SLIRP_SRC
# USB support
if [ -z "$SKIP_USB_BUILD" ]; then
build $USB_SRC
meson_build $USBREDIR_SRC
fi
# GPU support
build_angle
meson_build $EPOXY_REPO -Dtests=false -Dglx=no -Degl=yes
cmake_build $VULKAN_LOADER_REPO -D UPDATE_DEPS=On
# strip the minor versions
VULKAN_DYLIB="$PREFIX/lib/libvulkan.1.dylib"
mv "$(dirname $VULKAN_DYLIB)/$(readlink $VULKAN_DYLIB)" "$VULKAN_DYLIB"
if [ "$PLATFORM" == "macos" ]; then
VIRGL_RENDER_SERVER_MODE="process"
else
VIRGL_RENDER_SERVER_MODE="thread"
fi
meson_darwin_build $VIRGLRENDERER_REPO -Dtests=false -Dcheck-gl-errors=false -Dvenus=true -Dneptune=true -Dvulkan-dload=false -Drender-server-mode="$VIRGL_RENDER_SERVER_MODE"
# Hypervisor for iOS
if [ "$PLATFORM" == "ios" ] || [ "$PLATFORM" == "ios_simulator" ]; then
build_hypervisor
fi
}
build_spice_client () {
meson_build $LIBUCONTEXT_REPO -Ddefault_library=static -Dfreestanding=true
meson_build $JSON_GLIB_SRC -Dintrospection=disabled
build $XML2_SRC --enable-shared=no --without-python
meson_build $SOUP_SRC -Dsysprof=disabled -Dtls_check=false -Dintrospection=disabled
meson_build $PHODAV_SRC
meson_build $SPICE_CLIENT_SRC -Dcoroutine=libucontext
}
patch_vulkan_icd() {
local icd_file="$1"
if [ "$PLATFORM" == "macos" ]; then
sed -i '' -E '
s|("library_path"[[:space:]]*:[[:space:]]*")[^"]*/lib([^"/]+)\.dylib(")|\1../../../Frameworks/\2.framework/Versions/Current/\2\3|
' "$icd_file"
else
sed -i '' -E '
s|("library_path"[[:space:]]*:[[:space:]]*")[^"]*/lib([^"/]+)\.dylib(")|\1../../Frameworks/\2.framework/\2\3|
' "$icd_file"
fi
}
build_moltenvk() {
pushd "$BUILD_DIR/MoltenVK.git"
# for xcpretty if installed
if which ruby >/dev/null && which gem >/dev/null; then
PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH"
fi
if [ ! -z "$DEBUG" ]; then
DEBUG_FLAGS="-debug"
fi
case $PLATFORM in
ios_simulator* )
MVK_PLATFORM="iossim"
;;
ios* )
MVK_PLATFORM="ios"
;;
visionos_simulator* )
MVK_PLATFORM="visionossim"
;;
visionos* )
MVK_PLATFORM="visionos"
;;
macos )
MVK_PLATFORM="macos"
;;
esac
env -i PATH=$PATH HOME=$HOME LANG=en_US.UTF-8 ./fetchDependencies --$MVK_PLATFORM -v
env -i PATH=$PATH HOME=$HOME LANG=en_US.UTF-8 make $MVK_PLATFORM$DEBUG_FLAGS
if [ "$PLATFORM" == "macos" ]; then
$(xcrun --sdk $SDK --find lipo) "Package/$BUILD_CONFIGURATION/MoltenVK/dylib/macOS/libMoltenVK.dylib" -extract $ARCH -output "$PREFIX/lib/libMoltenVK.dylib"
else
find "Package/$BUILD_CONFIGURATION/MoltenVK/dynamic/MoltenVK.xcframework" -name "MoltenVK.framework" -exec cp -a \{\} "$PREFIX/Frameworks/" \;
fi
cp -a "MoltenVK/icd/MoltenVK_icd.json" "$PREFIX/share/vulkan/icd.d/"
popd
}
build_mesa_host () {
pushd "$BUILD_DIR/mesa.git"
HOST_PATH="$(brew --prefix llvm)/bin:$CLEAN_PATH"
env -i PATH="$HOST_PATH" meson host_build --prefix="$PREFIX/host" --buildtype=release \
-Dllvm=enabled -Dstrip=true -Dopengl=false -Dgallium-drivers= -Dvulkan-drivers= -Dmesa-clc=enabled -Dinstall-mesa-clc=true
env -i PATH="$HOST_PATH" meson compile -C host_build -j $NCPU
env -i PATH="$HOST_PATH" meson install -C host_build
popd
}
build_vulkan_drivers () {
mkdir -p "$PREFIX/share/vulkan/icd.d"
build_mesa_host
meson_darwin_build $MESA_REPO -Dmesa-clc=system -Dgallium-drivers= -Dvulkan-drivers=kosmickrisp -Dplatforms=macos
patch_vulkan_icd "$PREFIX/share/vulkan/icd.d/kosmickrisp_mesa_icd.$ARCH.json"
mv "$PREFIX/share/vulkan/icd.d/kosmickrisp_mesa_icd.$ARCH.json" "$PREFIX/share/vulkan/icd.d/kosmickrisp_mesa_icd.json"
build_moltenvk
patch_vulkan_icd "$PREFIX/share/vulkan/icd.d/MoltenVK_icd.json"
}
build_d3d_drivers () {
LLVM15_NAME=$(basename "${LLVM15_SRC%.tar.*}")
cmake_build "$BUILD_DIR/$LLVM15_NAME/llvm" -DLLVM_ENABLE_ZSTD=Off -DLLVM_TARGETS_TO_BUILD="" -DLLVM_BUILD_TOOLS=Off -DLLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO=Off
(
case $PLATFORM in
ios* )
DXMT_SDKMINVER="16.0"
;;
macos )
DXMT_SDKMINVER="13.0"
;;
* )
DXMT_SDKMINVER="$SDKMINVER"
;;
esac
DXMT_CFLAGS_TARGET="${CFLAGS_TARGET/$SDKMINVER/$DXMT_SDKMINVER}"
CC="${CC/$CFLAGS_TARGET/$DXMT_CFLAGS_TARGET}"
CPPFLAGS="${CPPFLAGS/$CFLAGS_TARGET/$DXMT_CFLAGS_TARGET}"
CXXFLAGS="${CXXFLAGS/$CFLAGS_TARGET/$DXMT_CFLAGS_TARGET}"
OBJCFLAGS="${OBJCFLAGS/$CFLAGS_TARGET/$DXMT_CFLAGS_TARGET}"
LDFLAGS="${LDFLAGS/$CFLAGS_TARGET/$DXMT_CFLAGS_TARGET}"
MESON_CROSS_SUFFIX="-dxmt"
meson_darwin_build $DXMT_REPO -Dnative_llvm_path="$PREFIX"
)
if [ "$ARCH" == "x86_64" -a "$PLATFORM" == "macos" ]; then
meson_build $D3DMETAL_REPO -Dtests=disabled
else
# empty placeholder file
$CC -dynamiclib -x c /dev/null -o "$PREFIX/lib/libd3dmetal-native.dylib"
fi
}
fixup_imports() {
_file=$1
_list=$(otool -L "$_file" | tail -n +2 | cut -d ' ' -f 1 | awk '{$1=$1};1')
for g in $_list
do
base=$(basename "$g")
basefilename=${base%.*}
libname=${basefilename#lib*}
dir=$(dirname "$g")
if [ "$dir" == "$PREFIX/lib" ] || [ "$dir" == "@rpath" ]; then
if [ "$PLATFORM" == "macos" ]; then
newname="@rpath/$libname.framework/Versions/A/$libname"
else
newname="@rpath/$libname.framework/$libname"
fi
install_name_tool -change "$g" "$newname" "$_file"
fi
done
}
fixup_dylib () {
FILE=$1
BASE=$(basename "$FILE")
BASEFILENAME=${BASE%.*}
LIBNAME=${BASEFILENAME#lib*}
BUNDLE_ID="com.utmapp.${LIBNAME//_/-}"
FRAMEWORKNAME="$LIBNAME.framework"
BASEFRAMEWORKPATH="$PREFIX/Frameworks/$FRAMEWORKNAME"
if [ "$PLATFORM" == "macos" ]; then
FRAMEWORKPATH="$BASEFRAMEWORKPATH/Versions/A"
INFOPATH="$FRAMEWORKPATH/Resources"
else
FRAMEWORKPATH="$BASEFRAMEWORKPATH"
INFOPATH="$FRAMEWORKPATH"
fi
NEWFILE="$FRAMEWORKPATH/$LIBNAME"
OLDIFS=$IFS
IFS=$'\n'
mkdir -p "$FRAMEWORKPATH"
mkdir -p "$INFOPATH"
cp -a "$FILE" "$NEWFILE"
MINOSVER=$(vtool -show-build-version "$FILE" 2>/dev/null | awk '/minos/ {print $2; exit}')
[ -n "$MINOSVER" ] || MINOSVER="$SDKMINVER"
/usr/libexec/PlistBuddy -c "Add :CFBundleExecutable string $LIBNAME" "$INFOPATH/Info.plist" || true
/usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string $BUNDLE_ID" "$INFOPATH/Info.plist" || true
/usr/libexec/PlistBuddy -c "Add :MinimumOSVersion string $MINOSVER" "$INFOPATH/Info.plist" || true
/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string 1" "$INFOPATH/Info.plist" || true
/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string 1.0" "$INFOPATH/Info.plist" || true
if [ "$PLATFORM" == "macos" ]; then
ln -sf "A" "$BASEFRAMEWORKPATH/Versions/Current"
ln -sf "Versions/Current/Resources" "$BASEFRAMEWORKPATH/Resources"
ln -sf "Versions/Current/$LIBNAME" "$BASEFRAMEWORKPATH/$LIBNAME"
fi
newname="@rpath/$FRAMEWORKNAME/$LIBNAME"
install_name_tool -id "$newname" "$NEWFILE"
fixup_imports "$NEWFILE"
IFS=$OLDIFS
}
fixup_all () {
OLDIFS=$IFS
IFS=$'\n'
FILES=$(find "$SYSROOT_DIR/lib" -type f -maxdepth 1 -name "*.dylib")
for f in $FILES
do
echo "${GREEN}Fixing up $f...${NC}"
fixup_dylib $f
done
FILES=$(find "$SYSROOT_DIR/libexec" -type f -maxdepth 1 -perm +111)
for f in $FILES
do
echo "${GREEN}Fixing up $f...${NC}"
fixup_imports $f
done
IFS=$OLDIFS
}
remove_shared_gst_plugins () {
find "$SYSROOT_DIR/lib/gstreamer-1.0" -name '*.dylib' -exec rm \{\} \;
}
# parse args
ARCH=
REBUILD=
QEMU_DIR=
REDOWNLOAD=
PLATFORM_FAMILY_NAME=
while [ "x$1" != "x" ]; do
case $1 in
-a )
ARCH=$(echo "$2" | tr '[:upper:]' '[:lower:]')
shift
;;
-d | --download )
REDOWNLOAD=y
;;
-r | --rebuild )
REBUILD=y
;;
-q | --qemu )
QEMU_DIR="$2"
shift
;;
-p )
PLATFORM=$(echo "$2" | tr '[:upper:]' '[:lower:]')
shift
;;
-x | --debug )
DEBUG=1
;;
* )
usage
;;
esac
shift
done
if [ "x$ARCH" == "x" ]; then
ARCH=arm64
fi
export ARCH
if [ "x$PLATFORM" == "x" ]; then
PLATFORM=ios
fi
# Export supplied CHOST or deduce by ARCH
if [ -z "$CHOST" ]; then
case $ARCH in
armv7 | armv7s )
CPU=arm
;;
arm64 )
CPU=aarch64
;;
i386 | x86_64 )
CPU=$ARCH
;;
* )
usage
;;
esac
fi
CHOST=$CPU-apple-darwin
export CHOST
case $PLATFORM in
ios* | visionos* )
if [ -z "$SDKMINVER" ]; then
case $PLATFORM in
ios* )
SDKMINVER="$IOS_SDKMINVER"
;;
visionos* )
SDKMINVER="$VISIONOS_SDKMINVER"
;;
esac
fi
HVF_FLAGS="--disable-hvf"
case $PLATFORM in
ios_simulator* )
SDK=iphonesimulator
CFLAGS_TARGET="-target $ARCH-apple-ios$SDKMINVER-simulator"
PLATFORM_FAMILY_PREFIX="iOS_Simulator"
;;
ios* )
SDK=iphoneos
CFLAGS_TARGET="-target $ARCH-apple-ios$SDKMINVER"
PLATFORM_FAMILY_PREFIX="iOS"
HVF_FLAGS="--enable-hvf-private"
;;
visionos_simulator* )
SDK=xrsimulator
CFLAGS_TARGET="-target $ARCH-apple-xros$SDKMINVER-simulator"
PLATFORM_FAMILY_PREFIX="visionOS_Simulator"
;;
visionos* )
SDK=xros
CFLAGS_TARGET="-target $ARCH-apple-xros$SDKMINVER"
PLATFORM_FAMILY_PREFIX="visionOS"
;;
esac
case $PLATFORM in
*-tci )
if [ "$ARCH" == "arm64" ]; then
TCI_BUILD_FLAGS="--enable-tcg-threaded-interpreter --target-list=aarch64-softmmu,i386-softmmu,ppc-softmmu,ppc64-softmmu,riscv64-softmmu,x86_64-softmmu,m68k-softmmu --extra-cflags=-Wno-unused-command-line-argument --extra-ldflags=-Wl,-no_deduplicate --extra-ldflags=-Wl,-random_uuid --extra-ldflags=-Wl,-no_compact_unwind"
else
TCI_BUILD_FLAGS="--enable-tcg-interpreter"
fi
PLATFORM_FAMILY_NAME="$PLATFORM_FAMILY_PREFIX-TCI"
SKIP_USB_BUILD=1
;;
* )
PLATFORM_FAMILY_NAME="$PLATFORM_FAMILY_PREFIX"
;;
esac
QEMU_PLATFORM_BUILD_FLAGS="--enable-shared-lib --disable-cocoa --disable-sdl --disable-coreaudio --disable-slirp-smbd --enable-ucontext --with-coroutine=libucontext $HVF_FLAGS $TCI_BUILD_FLAGS"
;;
macos )
if [ -z "$SDKMINVER" ]; then
SDKMINVER="$MAC_SDKMINVER"
fi
SDK=macosx
CFLAGS_TARGET="-target $ARCH-apple-macos$SDKMINVER"
# libtool drops -target when linking C++ libraries so set the default as well
export MACOSX_DEPLOYMENT_TARGET="$SDKMINVER"
PLATFORM_FAMILY_NAME="macOS"
QEMU_PLATFORM_BUILD_FLAGS="--enable-shared-lib --disable-cocoa --disable-sdl --cpu=$CPU"
;;
* )
usage
;;
esac
if [ -z "$DEBUG" ]; then
QEMU_DEBUG_FLAGS="--disable-debug-info"
fi
export SDK
export SDKMINVER
# Setup directories
BASEDIR="$(dirname "$(realpath $0)")"
BUILD_DIR="build-$PLATFORM_FAMILY_NAME-$ARCH"
SYSROOT_DIR="sysroot-$PLATFORM_FAMILY_NAME-$ARCH"
PATCHES_DIR="$BASEDIR/../patches"
# Include URL list
source "$PATCHES_DIR/sources"
if [ -z "$QEMU_DIR" ]; then
FILE="$(basename $QEMU_SRC)"
QEMU_DIR="$BUILD_DIR/${FILE%.tar.*}"
elif [ ! -d "$QEMU_DIR" ]; then
echo "${RED}Cannot find: ${QEMU_DIR}...${NC}"
exit 1
else
QEMU_DIR="$(realpath "$QEMU_DIR")"
fi
[ -d "$SYSROOT_DIR" ] || mkdir -p "$SYSROOT_DIR"
PREFIX="$(realpath "$SYSROOT_DIR")"
# Export supplied SDKVERSION or use system default
SDKNAME=$(basename $(xcrun --sdk $SDK --show-sdk-platform-path) .platform)
if [ ! -z "$SDKVERSION" ]; then
SDKROOT=$(xcrun --sdk $SDK --show-sdk-platform-path)"/Developer/SDKs/$SDKNAME$SDKVERSION.sdk"
else
SDKVERSION=$(xcrun --sdk $SDK --show-sdk-version) # current version
SDKROOT=$(xcrun --sdk $SDK --show-sdk-path) # current version
fi
if [ -z "$SDKMINVER" ]; then
SDKMINVER="$SDKVERSION"
fi
# Set NCPU
if [ -z "$NCPU" ] || [ $NCPU -eq 0 ]; then
NCPU="$(sysctl -n hw.ncpu)"
fi
export NCPU
# Export tools
CC="$(xcrun --sdk $SDK --find gcc) $CFLAGS_TARGET"
CPP=$(xcrun --sdk $SDK --find gcc)" -E"
CXX=$(xcrun --sdk $SDK --find g++)
OBJCC=$(xcrun --sdk $SDK --find clang)
LD=$(xcrun --sdk $SDK --find ld)
AR=$(xcrun --sdk $SDK --find ar)
NM=$(xcrun --sdk $SDK --find nm)
RANLIB=$(xcrun --sdk $SDK --find ranlib)
STRIP=$(xcrun --sdk $SDK --find strip)
export CC
export CPP
export CXX
export OBJCC
export LD
export AR
export NM
export RANLIB
export STRIP
export PREFIX
if [ -z "$DEBUG" ]; then
DEBUG_FLAGS=
BUILD_CONFIGURATION="Release"
else
DEBUG_FLAGS="-g -O0"
BUILD_CONFIGURATION="Debug"
fi
# Flags
CFLAGS="$CFLAGS -arch $ARCH -isysroot $SDKROOT -I$PREFIX/include -F$PREFIX/Frameworks $DEBUG_FLAGS"
CPPFLAGS="$CPPFLAGS -arch $ARCH -isysroot $SDKROOT -I$PREFIX/include -F$PREFIX/Frameworks $CFLAGS_TARGET $DEBUG_FLAGS"
CXXFLAGS="$CXXFLAGS -arch $ARCH -isysroot $SDKROOT -I$PREFIX/include -F$PREFIX/Frameworks $CFLAGS_TARGET $DEBUG_FLAGS"
OBJCFLAGS="$OBJCFLAGS -arch $ARCH -isysroot $SDKROOT -I$PREFIX/include -F$PREFIX/Frameworks $CFLAGS_TARGET $DEBUG_FLAGS"
LDFLAGS="$LDFLAGS -arch $ARCH -isysroot $SDKROOT -L$PREFIX/lib -F$PREFIX/Frameworks $CFLAGS_TARGET $DEBUG_FLAGS"
export CFLAGS
export CPPFLAGS
export CXXFLAGS
export OBJCFLAGS
export LDFLAGS
# Same reason as the has_function_* properties in the meson cross file: AC_CHECK_FUNCS
# declares its own prototype and misses the 27.0 SDK availability attribute.
export ac_cv_func_pipe2=no
export ac_cv_func_dup3=no
check_env
echo "${GREEN}Starting build for ${PLATFORM_FAMILY_NAME} ${ARCH} [${NCPU} jobs]${NC}"
if [ ! -f "$BUILD_DIR/BUILD_SUCCESS" ]; then
if [ ! -z "$REBUILD" ]; then
echo "${RED}Error, no previous successful build found.${NC}"
exit 1
fi
fi
if [ -z "$REBUILD" ]; then
download_all
fi
echo "${GREEN}Deleting old sysroot!${NC}"
rm -rf "$PREFIX/"*
rm -f "$BUILD_DIR/BUILD_SUCCESS"
rm -f "$BUILD_DIR"/meson*.cross
rm -f "$BUILD_DIR/cross.cmake"
mkdir -p "$PREFIX/Frameworks"
copy_private_headers
build_pkg_config
build_qemu_dependencies
build $QEMU_DIR --cross-prefix="" $QEMU_PLATFORM_BUILD_FLAGS $QEMU_DEBUG_FLAGS
build_spice_client
build_vulkan_drivers
build_d3d_drivers
fixup_all
remove_shared_gst_plugins # another hack...
echo "${GREEN}All done!${NC}"
touch "$BUILD_DIR/BUILD_SUCCESS"