From 97b5d2de7a00baa01be948e83a865fb38f6d3d8f Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 1 May 2022 16:10:47 -0300 Subject: [PATCH] Jenkins: Universal macOS building bringup --- .ci/build.sh | 177 ++++++++++++++++++++++++++++++++-- .ci/dependencies_macports.txt | 18 ++-- .gitignore | 8 +- 3 files changed, 184 insertions(+), 19 deletions(-) diff --git a/.ci/build.sh b/.ci/build.sh index 44c95f034..c8ab66e08 100644 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -37,7 +37,9 @@ # build_arch x86_64 (or arm64) # universal_archs (blank) # ui_interactive no -# macosx_deployment_target 10.13 +# macosx_deployment_target 10.13 (for x86_64, or 11.0 for arm64) +# - For universal building on Apple Silicon hardware, install native MacPorts on the default +# /opt/local and Intel MacPorts on /opt/intel, then tell build.sh to build for "x86_64+arm64" # - port is called through sudo to manage dependencies; make sure it is configured # as NOPASSWD in /etc/sudoers if you're doing unattended builds # @@ -100,6 +102,7 @@ cwd=$(pwd) package_name= arch= tarball_name= +skip_archive=0 strip=0 cmake_flags= while [ $# -gt 0 ] @@ -113,6 +116,11 @@ do shift ;; + -n) + shift + skip_archive=1 + ;; + -s) shift tarball_name="$1" @@ -330,15 +338,164 @@ then # macOS lacks nproc, but sysctl can do the same job. alias nproc='sysctl -n hw.logicalcpu' + # Handle universal build. + if echo "$arch" | grep -q '+' + then + # Create temporary directory for merging app bundles. + rm -rf archive_tmp_universal + mkdir archive_tmp_universal + + # Build for each architecture. + merge_src= + for arch_universal in $(echo "$arch" | tr '+' ' ') + do + # Run build for the architecture. + strip_arg= + [ $strip -ne 0 ] && strip_arg="-t " + case $arch_universal in # workaround: force new dynarec on for ARM + arm32 | arm64) cmake_flags_extra="-D NEW_DYNAREC=ON";; + *) cmake_flags_extra=;; + esac + zsh -lc 'exec "'"$0"'" -n -b "universal part" "'"$arch_universal"'" '"$strip_arg""$cmake_flags"' '"$cmake_flags_extra" + status=$? + + if [ $status -eq 0 ] + then + # Move app bundle to the temporary directory. + app_bundle_name="archive_tmp/$(ls archive_tmp | grep '.app$')" + mv "$app_bundle_name" "archive_tmp_universal/$arch_universal.app" + status=$? + + # Merge app bundles. + if [ -z "$merge_src" ] + then + # This is the first bundle, nothing to merge with. + merge_src="$arch_universal" + else + # Merge previous bundle with this one. + merge_dest="$merge_src+$arch_universal" + echo [-] Merging app bundles [$merge_src] and [$arch_universal] into [$merge_dest] + + # Merge directory structures. + (cd "archive_tmp_universal/$merge_src.app" && find . -type d && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type d && cd ../..) | sort > universal_listing.txt + cat universal_listing.txt | uniq | while IFS= read line + do + echo '> Directory:' "$line" + mkdir -p "archive_tmp_universal/$merge_dest.app/$line" + done + + # Create merged file listing. + (cd "archive_tmp_universal/$merge_src.app" && find . -type f && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type f && cd ../..) | sort > universal_listing.txt + + # Move files that only exist on one bundle. + cat universal_listing.txt | uniq -u | while IFS= read line + do + if [ -e "archive_tmp_universal/$merge_src.app/$line" ] + then + file_src="$merge_src" + else + file_src="$arch_universal" + fi + echo '> Only on' "[$file_src]:" "$line" + cp -p "archive_tmp_universal/$file_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line" + done + + # Move or lipo files that exist on both bundles. + cat universal_listing.txt | uniq -d | while IFS= read line + do + # Merge identical files. + if cmp -s "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$arch_universal.app/$line" + then + echo '> Identical:' "$line" + cp -p "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line" + elif lipo -create -output "archive_tmp_universal/$merge_dest.app/$line" "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$arch_universal.app/$line" 2> /dev/null + then + echo '> Merged:' "$line" + else + echo '> Copied from' "[$merge_src]:" "$line" + cp -p "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line" + fi + done + + # Merge symlinks. + (cd "archive_tmp_universal/$merge_src.app" && find . -type l && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type l && cd ../..) | sort > universal_listing.txt + cat universal_listing.txt | uniq | while IFS= read line + do + if [ -e "archive_tmp_universal/$merge_src.app/$line" ] + then + file_src="$merge_src" + else + file_src="$arch_universal" + fi + link_dest="$(readlink "archive_tmp_universal/$file_src.app/$line")" + echo '> Symlink:' "$line" '=>' "$link_dest" + ln -s "$link_dest" "archive_tmp_universal/$merge_dest.app/$line" + done + + # Merge a subsequent bundle with this one. + merge_src="$merge_dest" + fi + fi + + if [ $status -ne 0 ] + then + echo [!] Aborting universal build: [$arch_universal] failed with status [$status] + exit $status + fi + done + + # Rename final app bundle. + rm -rf archive_tmp + mkdir archive_tmp + mv "archive_tmp_universal/$merge_src.app" "$app_bundle_name" + + # Sign final app bundle. + codesign --force --deep -s - "$app_bundle_name" + + # Create zip. + cd archive_tmp + zip -r "$cwd/$package_name.zip" . + status=$? + + # Check if the archival succeeded. + if [ $status -ne 0 ] + then + echo [!] Artifact archive creation failed with status [$status] + exit 7 + fi + + # All good. + echo [-] Universal build of [$package_name] for [$arch] with flags [$cmake_flags] successful + exit 0 + fi + + # Switch into the correct architecture if required. + case $arch in + x86_64) arch_mac="i386";; + *) arch_mac="$arch";; + esac + if [ "$(arch)" != "$arch" -a "$(arch)" != "$arch_mac" ] + then + # Call build with the correct architecture. + echo [-] Switching to architecture [$arch] + cd "$cwd" + strip_arg= + [ $strip -ne 0 ] && strip_arg="-t " + arch -"$arch" zsh -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$strip_arg""$cmake_flags" + exit $? + fi + echo [-] Using architecture [$(arch)] + # Locate the MacPorts prefix. macports="/opt/local" [ -e "/opt/$arch/bin/port" ] && macports="/opt/$arch" [ "$arch" = "x86_64" -a -e "/opt/intel/bin/port" ] && macports="/opt/intel" + export PATH="$macports/bin:$macports/sbin:$PATH" # Install dependencies. echo [-] Installing dependencies through MacPorts - sudo $macports/bin/port selfupdate - sudo $macports/bin/port install $(cat .ci/dependencies_macports.txt) + sudo "$macports/bin/port" selfupdate + sudo "$macports/bin/port" install $(cat .ci/dependencies_macports.txt) # Point CMake to the toolchain file. [ -e "cmake/$toolchain.cmake" ] && cmake_flags_extra="$cmake_flags_extra -D \"CMAKE_TOOLCHAIN_FILE=cmake/$toolchain.cmake\"" @@ -563,8 +720,8 @@ then unzip -j discord_game_sdk.zip "lib/$arch_discord/discord_game_sdk.dylib" -d "archive_tmp/"*".app/Contents/Frameworks" [ ! -e "archive_tmp/"*".app/Contents/Frameworks/discord_game_sdk.dylib" ] && echo [!] No Discord Game SDK for architecture [$arch_discord] - # Sign app bundle. - codesign --force --deep -s - "archive_tmp/"*".app" + # Sign app bundle, unless we're in an universal build. + [ $skip_archive -eq 0 ] && codesign --force --deep -s - "archive_tmp/"*".app" fi else cwd_root=$(pwd) @@ -698,6 +855,13 @@ then exit 6 fi +# Stop if artifact archive creation was disabled. +if [ $skip_archive -ne 0 ] +then + echo [-] Skipping artifact archive creation + exit 0 +fi + # Produce artifact archive. echo [-] Creating artifact archive if is_windows @@ -708,7 +872,7 @@ then status=$? elif is_mac then - # Create zip. (TODO: dmg) + # Create zip. cd archive_tmp zip -r "$cwd/$package_name.zip" . status=$? @@ -771,7 +935,6 @@ EOF status=$? fi fi -cd .. # Check if the archival succeeded. if [ $status -ne 0 ] diff --git a/.ci/dependencies_macports.txt b/.ci/dependencies_macports.txt index 4171a0a69..086684d2a 100644 --- a/.ci/dependencies_macports.txt +++ b/.ci/dependencies_macports.txt @@ -1,10 +1,10 @@ -cmake@3.22.3_0 -pkgconfig@0.29.2_0 -ninja@1.10.2_4 -freetype@2.11.1_0 -libsdl2@2.0.20_0 -libpng@1.6.37_0 -openal-soft@1.21.1_0 -rtmidi@5.0.0_0 -qt5@5.15.3_0 +cmake +pkgconfig +ninja +freetype +libsdl2 +libpng +openal-soft +rtmidi +qt5 wget diff --git a/.gitignore b/.gitignore index a38da5deb..38fdb6d26 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ # CMake -/CMakeUserPresets.json -/CMakeCache.txt -/build +CMakeUserPresets.json +CMakeCache.txt CMakeFiles +/build Makefile *.a /src/*.exe @@ -26,9 +26,11 @@ Makefile # Build scripts /archive_tmp +/archive_tmp_universal /static2dll.* /pacman.txt /deps.txt +/universal_listing.txt /VERSION *.zip *.tar