From 07236818547fe53bd7056431403a095da65071d3 Mon Sep 17 00:00:00 2001 From: Sergey Minakov Date: Sat, 13 Feb 2021 13:13:24 +0300 Subject: [PATCH] tvOS classical build support --- Dockerfile.tvos | 39 +++++ Dockerfile.xcode | 25 ++- build.sh | 6 +- files/tvos_toolchain/tvos_example.sh | 220 +++++++++++++++++++++++++++ files/tvos_toolchain/tvos_wrapper.c | 195 ++++++++++++++++++++++++ upload.sh | 1 + 6 files changed, 482 insertions(+), 4 deletions(-) create mode 100644 Dockerfile.tvos create mode 100644 files/tvos_toolchain/tvos_example.sh create mode 100644 files/tvos_toolchain/tvos_wrapper.c diff --git a/Dockerfile.tvos b/Dockerfile.tvos new file mode 100644 index 0000000..d62159c --- /dev/null +++ b/Dockerfile.tvos @@ -0,0 +1,39 @@ +ARG img_version +FROM godot-osx:${img_version} + +ARG mono_version + +ENV TVOS_SDK=14.2 + +RUN dnf -y install --setopt=install_weak_deps=False \ + automake autoconf clang gcc gcc-c++ gcc-objc gcc-objc++ cmake libicu-devel libtool libxml2-devel llvm-devel openssl-devel perl python yasm + +RUN git clone --progress https://github.com/tpoechtrager/cctools-port.git && \ + cd /root/cctools-port && \ + git checkout 634a084377ee2e2932c66459b0396edf76da2e9f && \ + yes | cp -rf /root/files/tvos_toolchain/tvos_example.sh usage_examples/ios_toolchain/build.sh && \ + yes | cp -rf /root/files/tvos_toolchain/tvos_wrapper.c usage_examples/ios_toolchain/wrapper.c && \ + chmod +x usage_examples/ios_toolchain/build.sh + +RUN cd /root/cctools-port && \ + usage_examples/ios_toolchain/build.sh /root/files/AppleTVOS${TVOS_SDK}.sdk.tar.xz 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 && \ + sed -i 's#AppleTVOS#AppleTVSimulator#' usage_examples/ios_toolchain/build.sh && \ + sed -i 's#-mappletvos-version-min=#-mappletvsimulator-version-min=#' usage_examples/ios_toolchain/wrapper.c && \ + sed -i 's#^TRIPLE=.*#TRIPLE="x86_64-apple-darwin11"#' usage_examples/ios_toolchain/build.sh && \ + usage_examples/ios_toolchain/build.sh /root/files/AppleTVSimulator${TVOS_SDK}.sdk.tar.xz 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 + +ENV OSXCROSS_TVOS=not_nothing +ENV TVOSCROSS_ROOT=/root/ioscross +ENV PATH="/root/ioscross/arm64/bin:/root/ioscross/x86_64/bin:${PATH}" + +CMD /bin/bash diff --git a/Dockerfile.xcode b/Dockerfile.xcode index 382788e..d4989ec 100644 --- a/Dockerfile.xcode +++ b/Dockerfile.xcode @@ -15,6 +15,7 @@ RUN dnf -y install --setopt=install_weak_deps=False \ clang -O3 -llzma -lxar -I /usr/local/include pbzx.c -o pbzx CMD mkdir -p /root/xcode && \ + # macOS cd /root/xcode && \ xar -xf /root/files/Xcode_12.2.xip && \ /root/pbzx/pbzx -n Content | cpio -i && \ @@ -29,19 +30,39 @@ CMD mkdir -p /root/xcode && \ cd /tmp && \ tar -cJf /root/files/${OSX_SDK}.tar.xz ${OSX_SDK} && \ rm -rf ${OSX_SDK} && \ + # iOS cd /root/xcode && \ export IOS_SDK=iPhoneOS14.2.sdk && \ - export IOS_SIMULATOR_SDK=iPhoneSimulator14.2.sdk && \ cp -r Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk /tmp/${IOS_SDK} && \ mkdir -p /tmp/${IOS_SDK}/usr/include/c++ && \ cp -r Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 /tmp/${IOS_SDK}/usr/include/c++/ && \ cd /tmp && \ tar -cJf /root/files/${IOS_SDK}.tar.xz ${IOS_SDK} && \ rm -rf ${IOS_SDK} && \ + # iOS Simulator cd /root/xcode && \ + export IOS_SIMULATOR_SDK=iPhoneSimulator14.2.sdk && \ cp -r Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk /tmp/${IOS_SDK} && \ mkdir -p /tmp/${IOS_SDK}/usr/include/c++ && \ cp -r Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 /tmp/${IOS_SDK}/usr/include/c++/ && \ cd /tmp && \ tar -cJf /root/files/${IOS_SIMULATOR_SDK}.tar.xz ${IOS_SDK} && \ - rm -rf ${IOS_SDK} + rm -rf ${IOS_SDK} && \ + # tvOS + cd /root/xcode && \ + export TVOS_SDK=AppleTVOS14.2.sdk && \ + cp -r Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk /tmp/${TVOS_SDK} && \ + mkdir -p /tmp/${TVOS_SDK}/usr/include/c++ && \ + cp -r Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 /tmp/${TVOS_SDK}/usr/include/c++/ && \ + cd /tmp && \ + tar -cJf /root/files/${TVOS_SDK}.tar.xz ${TVOS_SDK} && \ + rm -rf ${TVOS_SDK} && \ + # tvOS Simulator + cd /root/xcode && \ + export TVOS_SIMULATOR_SDK=AppleTVSimulator14.2.sdk && \ + cp -r Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk /tmp/${TVOS_SIMULATOR_SDK} && \ + mkdir -p /tmp/${TVOS_SIMULATOR_SDK}/usr/include/c++ && \ + cp -r Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 /tmp/${TVOS_SIMULATOR_SDK}/usr/include/c++/ && \ + cd /tmp && \ + tar -cJf /root/files/${TVOS_SIMULATOR_SDK}.tar.xz ${TVOS_SIMULATOR_SDK} && \ + rm -rf ${TVOS_SIMULATOR_SDK} diff --git a/build.sh b/build.sh index 1a7b79a..3c8ce81 100755 --- a/build.sh +++ b/build.sh @@ -122,19 +122,21 @@ $podman_build_mono -t godot-android:${img_version} -f Dockerfile.android . 2>&1 XCODE_SDK=12.2 OSX_SDK=11.0 IOS_SDK=14.2 -if [ ! -e files/MacOSX${OSX_SDK}.sdk.tar.xz ] || [ ! -e files/iPhoneOS${IOS_SDK}.sdk.tar.xz ] || [ ! -e files/iPhoneSimulator${IOS_SDK}.sdk.tar.xz ]; then +TVOS_SDK=14.2 +if [ ! -e files/MacOSX${OSX_SDK}.sdk.tar.xz ] || [ ! -e files/iPhoneOS${IOS_SDK}.sdk.tar.xz ] || [ ! -e files/iPhoneSimulator${IOS_SDK}.sdk.tar.xz ] || [ ! -e files/AppleTVOS${TVOS_SDK}.sdk.tar.xz ] || [ ! -e files/AppleTVSimulator${TVOS_SDK}.sdk.tar.xz ]; then if [ ! -e files/Xcode_${XCODE_SDK}.xip ]; then echo "files/Xcode_${XCODE_SDK}.xip is required. It can be downloaded from https://developer.apple.com/download/more/ with a valid apple ID." exit 1 fi - echo "Building OSX and iOS SDK packages. This will take a while" + echo "Building OSX, iOS and tvOS SDK packages. This will take a while" $podman_build -t godot-xcode-packer:${img_version} -f Dockerfile.xcode -v ${files_root}:/root/files . 2>&1 | tee logs/xcode.log $podman run -it --rm -v ${files_root}:/root/files godot-xcode-packer:${img_version} 2>&1 | tee logs/xcode_packer.log fi $podman_build_mono -t godot-osx:${img_version} -f Dockerfile.osx . 2>&1 | tee logs/osx.log $podman_build_mono -t godot-ios:${img_version} -f Dockerfile.ios . 2>&1 | tee logs/ios.log +$podman_build_mono -t godot-tvos:${img_version} -f Dockerfile.tvos . 2>&1 | tee logs/tvos.log if [ ! -e files/msvc2017.tar ]; then echo diff --git a/files/tvos_toolchain/tvos_example.sh b/files/tvos_toolchain/tvos_example.sh new file mode 100644 index 0000000..d54b155 --- /dev/null +++ b/files/tvos_toolchain/tvos_example.sh @@ -0,0 +1,220 @@ +#!/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 + LLVM_DSYMUTIL=llvm-dsymutil +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 extract() +{ + echo "extracting $(basename $1) ..." + local tarflags="xf" + + case $1 in + *.tar.xz) + xz -dc $1 | tar $tarflags - + ;; + *.tar.gz) + gunzip -dc $1 | tar $tarflags - + ;; + *.tar.bz2) + bzip2 -dc $1 | tar $tarflags - + ;; + *) + echo "unhandled archive type" 1>&2 + exit 1 + ;; + esac +} + +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 2 ]; then + echo "usage: $0 AppleTVOS.sdk.tar* " 1>&2 + echo "i.e. $0 /path/to/AppleTVOS.sdk.tar.xz armv7" 1>&2 + exit 1 +fi + +TRIPLE="arm-apple-darwin11" +TARGETDIR="$PWD/target" +SDKDIR="$TARGETDIR/SDK" + +if [ -d $TARGETDIR ]; then + echo "cleaning up ..." + rm -rf $TARGETDIR +fi + +mkdir -p $TARGETDIR +mkdir -p $TARGETDIR/bin +mkdir -p $SDKDIR + +echo "" +echo "*** extracting SDK ***" +echo "" + +pushd $SDKDIR &>/dev/null +SDK_VERSION=$(echo $1 | grep -P -o "[0-9][0-9].[0-9]+" | head -1) +if [ -z "$SDK_VERSION" ]; then + SDK_VERSION=$(echo $1 | grep -P -o "[0-9].[0-9]+" | head -1) +fi +if [ -z "$SDK_VERSION" ]; then + echo "AppleTVOS Version must be in the SDK filename!" 1>&2 + exit 1 +fi +extract $1 +SYSLIB=$(find $SDKDIR -name libSystem.dylib -o -name libSystem.tbd | head -n1) +if [ -z "$SYSLIB" ]; then + echo "SDK should contain libSystem{.dylib,.tbd}" 1>&2 + exit 1 +fi +WRAPPER_SDKDIR=$(echo AppleTVOS*sdk | head -n1) +if [ -z "$WRAPPER_SDKDIR" ]; then + echo "broken SDK" 1>&2 + exit 1 +fi +popd &>/dev/null + +echo "" +echo "*** building wrapper ***" +echo "" + +OK=0 + +set +e +which $LLVM_DSYMUTIL &>/dev/null +if [ $? -eq 0 ]; then + case $($LLVM_DSYMUTIL --version | \ + grep "LLVM version" | head -1 | awk '{print $3}') in + 3.8*|3.9*|4.0*|5.0*|6.0*|7.0*|8.0*|9.0*) OK=1 ;; + esac +fi +set -e + +if [ $OK -eq 1 ]; then + ln -sf $(which $LLVM_DSYMUTIL) $TARGETDIR/bin/dsymutil + pushd $TARGETDIR/bin &>/dev/null + ln -sf $TRIPLE-lipo lipo + popd &>/dev/null +elif ! which dsymutil &>/dev/null; then + echo "int main(){return 0;}" | cc -xc -O2 -o $TARGETDIR/bin/dsymutil - +fi + +verbose_cmd cc -O2 -Wall -Wextra -pedantic wrapper.c \ + -DSDK_DIR=\"\\\"$WRAPPER_SDKDIR\\\"\" \ + -DTARGET_CPU=\"\\\"$2\\\"\" \ + -DOS_VER_MIN=\"\\\"$SDK_VERSION\\\"\" \ + -o $TARGETDIR/bin/$TRIPLE-clang + +pushd $TARGETDIR/bin &>/dev/null +verbose_cmd ln -sf $TRIPLE-clang $TRIPLE-clang++ +popd &>/dev/null + +echo "" +echo "*** building ldid ***" +echo "" + +rm -rf tmp + +mkdir -p tmp +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-libtapi ***" +echo "" + +pushd tmp &>/dev/null +git_clone_repository https://github.com/tpoechtrager/apple-libtapi.git 1100.0.11 +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 +make -j$JOBS && make install +popd &>/dev/null +popd &>/dev/null + +echo "" +echo "*** checking toolchain ***" +echo "" + +export PATH=$TARGETDIR/bin:$PATH + +echo "int main(){return 0;}" | $TRIPLE-clang -xc -O2 -o test - 1>/dev/null || exit 1 +rm test +echo "OK" + +echo "" +echo "*** all done ***" +echo "" +echo "do not forget to add $TARGETDIR/bin to your PATH variable" +echo "" diff --git a/files/tvos_toolchain/tvos_wrapper.c b/files/tvos_toolchain/tvos_wrapper.c new file mode 100644 index 0000000..d85c5b5 --- /dev/null +++ b/files/tvos_toolchain/tvos_wrapper.c @@ -0,0 +1,195 @@ +#ifndef TARGET_CPU +#define TARGET_CPU "armv7" +#endif + +#ifndef OS_VER_MIN +#define OS_VER_MIN "4.2" +#endif + +#ifndef SDK_DIR +#define SDK_DIR "" +#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 sdkpath[PATH_MAX+1]; + char osvermin[64]; + + char *compiler; + char *target; + + char *sdk; + char *cpu; + char *osmin; + + target_info(argv, &target, &compiler); + if (!get_executable_path(execpath, sizeof(execpath))) abort(); + snprintf(sdkpath, sizeof(sdkpath) - 1, "%s/../SDK/" SDK_DIR, execpath); + + env(&sdk, "IOS_SDK_SYSROOT", sdkpath); + env(&cpu, "IOS_TARGET_CPU", TARGET_CPU); + + env(&osmin, "IPHONEOS_DEPLOYMENT_TARGET", OS_VER_MIN); + unsetenv("IPHONEOS_DEPLOYMENT_TARGET"); + + snprintf(osvermin, sizeof(osvermin), "-mappletvos-version-min=%s", osmin); + + 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; + args[i++] = "-isysroot"; + args[i++] = sdk; + + if (cpu) + { + args[i++] = "-arch"; + args[i++] = cpu; + } + + args[i++] = osvermin; + args[i++] = "-mlinker-version=450.3"; + + 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/upload.sh b/upload.sh index 919de5b..d028277 100755 --- a/upload.sh +++ b/upload.sh @@ -22,6 +22,7 @@ $podman push godot-javascript:latest ${registry}/godot/javascript $podman push godot-xcode-packer:latest ${registry}/godot/xcode-packer $podman push godot-android:latest ${registry}/godot-private/android +$podman push godot-tvos:latest ${registry}/godot-private/tvos $podman push godot-ios:latest ${registry}/godot-private/ios $podman push godot-osx:latest ${registry}/godot-private/macosx $podman push godot-msvc:latest ${registry}/godot-private/uwp