diff options
Diffstat (limited to '.github/workflows/release-binaries.yml')
| -rw-r--r-- | .github/workflows/release-binaries.yml | 197 |
1 files changed, 171 insertions, 26 deletions
diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 8835844060..36be3f1c64 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -30,7 +30,7 @@ permissions: # clang and an older reader refuses it, so this has to stay at or above whatever produced # eden.profdata; bump it when a refreshed profile needs a newer LLVM. env: - PGO_LLVM_VERSION: '23' + PGO_LLVM_VERSION: "23" concurrency: group: release-binaries-${{ github.ref }} @@ -42,8 +42,9 @@ jobs: runs-on: ${{ matrix.runner }} env: CCACHE_DIR: ${{ github.workspace }}/.ccache - CCACHE_MAXSIZE: 1500M + CCACHE_MAXSIZE: 3000M SCCACHE_DIR: ${{ github.workspace }}/.sccache + SCCACHE_CACHE_SIZE: 3G strategy: fail-fast: false matrix: @@ -67,10 +68,12 @@ jobs: - platform: linux-aarch64-pgo runner: ubuntu-24.04-arm pgo: true + - platform: macos-arm64 + runner: macos-15 steps: - name: Check out source - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Linux dependencies if: startsWith(matrix.platform, 'linux') @@ -85,13 +88,26 @@ jobs: libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev \ spirv-tools spirv-headers libusb-1.0-0-dev \ libboost-dev libboost-fiber-dev libboost-context-dev \ - libopus-dev libasound2-dev ccache + libopus-dev libasound2-dev ccache \ + libxcb-cursor0 libxcb-icccm4 libxcb-image0 \ + libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libxcb-xkb1 + + # The packages docs/Deps.md lists for macOS, plus ccache. + - name: Install macOS dependencies + if: startsWith(matrix.platform, 'macos') + shell: bash + env: + HOMEBREW_NO_INSTALL_CLEANUP: 1 + run: | + brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz4 ninja \ + nlohmann-json openssl pkg-config qt@6 sdl3 speexdsp zlib zstd cmake catch2 molten-vk \ + vulkan-loader spirv-tools vulkan-utility-libraries ccache - name: Install Qt on Linux x86_64 if: startsWith(matrix.platform, 'linux') && runner.arch != 'ARM64' uses: jurplel/install-qt-action@v4 with: - version: '6.8.3' + version: "6.8.3" host: linux target: desktop arch: linux_gcc_64 @@ -102,7 +118,7 @@ jobs: if: startsWith(matrix.platform, 'linux') && runner.arch == 'ARM64' uses: jurplel/install-qt-action@v4 with: - version: '6.8.3' + version: "6.8.3" host: linux_arm64 target: desktop arch: linux_gcc_arm64 @@ -146,7 +162,7 @@ jobs: if: matrix.platform == 'windows-x86_64' uses: jurplel/install-qt-action@v4 with: - version: '6.8.3' + version: "6.8.3" host: windows target: desktop arch: win64_msvc2022_64 @@ -183,6 +199,7 @@ jobs: with: msystem: UCRT64 update: true + cache: true install: >- git make autoconf libtool automake-wrapper patch jq pactoys ninja pacboy: >- @@ -194,7 +211,7 @@ jobs: lerc:p graphite2:p libwebp:p libtiff:p brotli:p ccache:p - name: Cache CPM downloads - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .cache/cpm key: cpm-${{ runner.os }}-${{ hashFiles('cpmfile.json', 'CMakeLists.txt', 'src/**/CMakeLists.txt') }} @@ -204,7 +221,7 @@ jobs: # The sha in the key makes every run save a fresh cache (actions/cache never saves over an # exact hit), and restore-keys seeds it from the newest one of the same platform. - name: Cache compiler objects - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | .ccache @@ -266,6 +283,27 @@ jobs: -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + - name: Configure macOS + if: startsWith(matrix.platform, 'macos') + shell: bash + run: | + set -euo pipefail + cmake -S . -B build/release -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=OFF \ + -DYUZU_TESTS=OFF \ + -DYUZU_CMD=ON \ + -DYUZU_ROOM=OFF \ + -DYUZU_ROOM_STANDALONE=OFF \ + -DYUZU_USE_BUNDLED_QT=OFF \ + "-DCMAKE_PREFIX_PATH=$(brew --prefix qt@6);$(brew --prefix zlib)" \ + "-DOPENSSL_ROOT_DIR=$(brew --prefix openssl@3)" \ + -DVulkanHeaders_FORCE_BUNDLED=ON \ + -DVulkanUtilityLibraries_FORCE_BUNDLED=ON \ + -DENABLE_UPDATE_CHECKER=OFF \ + -DUSE_DISCORD_PRESENCE=OFF \ + -DUSE_CCACHE=ON + # MinGW build: system Qt and libraries from MSYS2, clang plus Eden's PGO profile. The profile # path is converted to its Windows form because clang runs with the MSYS mount underneath. - name: Configure MinGW PGO @@ -335,9 +373,6 @@ jobs: set -euo pipefail test -x build/release/bin/eglantine test -x build/release/bin/eden-cli - # Libraries Qt's xcb platform plugin needs, so linuxdeploy can resolve and bundle them. - sudo apt-get install -y --no-install-recommends libxcb-cursor0 libxcb-icccm4 libxcb-image0 \ - libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libxcb-xkb1 tools="$RUNNER_TEMP/linuxdeploy" mkdir -p "$tools" arch=$(uname -m) # aarch64 or x86_64 @@ -411,11 +446,70 @@ jobs: deps "$dll" done + # A self-contained app bundle: macdeployqt copies Qt and every other Homebrew library both + # programs load into the bundle, then the leftover Homebrew search paths are removed so a + # machine with Homebrew still uses the bundled copies. Ad-hoc signed, not notarized. + - name: Package macOS app + if: startsWith(matrix.platform, 'macos') + shell: bash + run: | + set -euo pipefail + app=build/release/bin/eglantine.app + test -x "$app/Contents/MacOS/eglantine" + test -x build/release/bin/eden-cli + cp build/release/bin/eden-cli "$app/Contents/MacOS/eden-cli" + "$(brew --prefix qt@6)/bin/macdeployqt" "$app" \ + -executable="$app/Contents/MacOS/eden-cli" -libpath="$(brew --prefix)/lib" \ + -always-overwrite -verbose=1 + # Qt's virtual keyboard input plugin pulls in the QML stack, which the emulator doesn't use. + rm -f "$app/Contents/PlugIns/platforminputcontexts/libqtvirtualkeyboardplugin.dylib" + binaries=$(find "$app/Contents" -type f \( -perm -u+x -o -name '*.dylib' \) \ + -exec sh -c 'file -b "$1" | grep -q Mach-O' _ {} \; -print) + for binary in $binaries; do + otool -l "$binary" | awk '/cmd LC_RPATH/ {getline; getline; print $2}' | + { grep -E '^/(opt/homebrew|usr/local)/' || true; } | while read -r rpath; do + install_name_tool -delete_rpath "$rpath" "$binary" 2> /dev/null + done + done + # Libraries that load their dependencies through @rpath find them in the bundle. + for program in eglantine eden-cli; do + install_name_tool -add_rpath @executable_path/../Frameworks \ + "$app/Contents/MacOS/$program" 2> /dev/null + done + leaks=$(for binary in $binaries; do + otool -L "$binary" | grep -E '^\s+/(opt/homebrew|usr/local)/' + otool -l "$binary" | awk '/cmd LC_RPATH/ {getline; getline; print $2}' | + grep -E '^/(opt/homebrew|usr/local)/' + done || true) + if [ -n "$leaks" ]; then + echo "References still pointing outside the bundle:" + echo "$leaks" | sort -u + exit 1 + fi + # macdeployqt invalidates the signatures. The programs get the entitlements when the + # tree has them (the Hypervisor CPU backend needs com.apple.security.hypervisor). + codesign --force --deep --sign - "$app" + if [ -f dist/eglantine.entitlements ]; then + codesign --force --sign - --entitlements dist/eglantine.entitlements \ + "$app/Contents/MacOS/eden-cli" + codesign --force --sign - --entitlements dist/eglantine.entitlements "$app" + fi + codesign --verify --deep --strict "$app" + ditto -c -k --keepParent "$app" "eglantine-${GITHUB_SHA}-${{ matrix.platform }}.zip" + ls -la "eglantine-${GITHUB_SHA}-${{ matrix.platform }}.zip" + # Also ship a .dmg (drag eglantine.app onto Applications). + dmgdir=$(mktemp -d) + ditto "$app" "$dmgdir/eglantine.app" + ln -s /Applications "$dmgdir/Applications" + hdiutil create -volname "Eglantine" -srcfolder "$dmgdir" -ov -format UDZO \ + "eglantine-${GITHUB_SHA}-${{ matrix.platform }}.dmg" + ls -la "eglantine-${GITHUB_SHA}-${{ matrix.platform }}.dmg" + # The artifact is the bin folder itself: GitHub zips artifacts on download, and uploading a # zip gave a zip inside a zip. The release job zips it once for the release. - name: Upload Windows binary if: matrix.platform == 'windows-x86_64' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: eglantine-${{ matrix.platform }}-${{ github.sha }} path: build/release/bin/ @@ -424,7 +518,7 @@ jobs: - name: Upload MinGW binary if: matrix.mingw - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: eglantine-${{ matrix.platform }}-${{ github.sha }} path: build/release/bin/ @@ -434,7 +528,7 @@ jobs: # Both Linux files go in one artifact: the tar.gz and the AppImage. - name: Upload Linux binary if: startsWith(matrix.platform, 'linux') - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: eglantine-${{ matrix.platform }}-${{ github.sha }} path: | @@ -444,6 +538,19 @@ jobs: compression-level: 0 retention-days: 7 + # Zipped with ditto beforehand: the bundle's framework symlinks don't survive artifact zipping. + - name: Upload macOS app + if: startsWith(matrix.platform, 'macos') + uses: actions/upload-artifact@v7 + with: + name: eglantine-${{ matrix.platform }}-${{ github.sha }} + path: | + eglantine-${{ github.sha }}-${{ matrix.platform }}.zip + eglantine-${{ github.sha }}-${{ matrix.platform }}.dmg + if-no-files-found: error + compression-level: 0 + retention-days: 7 + # Publishes every binary as a GitHub pre-release once every platform built: on pushes to nx2 # and nx2-experimental, and on manual runs unless "Publish the binaries as a GitHub release" is # unticked. @@ -456,7 +563,7 @@ jobs: contents: write steps: - name: Download binaries - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 with: pattern: eglantine-*-${{ github.sha }} path: artifacts @@ -466,33 +573,71 @@ jobs: run: | set -euo pipefail mkdir dist + # Asset names drop the commit sha: the release tag already identifies the build, and + # stable names let the notes table link to them. + strip_sha() { sed "s/-${GITHUB_SHA}//" <<< "$1"; } for artifact in artifacts/*/; do name=$(basename "$artifact") if compgen -G "$artifact*.AppImage" > /dev/null; then # Linux: ship the AppImage and the tar.gz as they are. - cp "$artifact"/*.AppImage "$artifact"/*.tar.gz dist/ + for file in "$artifact"*.AppImage "$artifact"*.tar.gz; do + cp "$file" "dist/$(strip_sha "$(basename "$file")")" + done + elif compgen -G "$artifact*.zip" > /dev/null; then + for file in "$artifact"*.zip "$artifact"*.dmg; do + [[ -e "$file" ]] && cp "$file" "dist/$(strip_sha "$(basename "$file")")" + done else - (cd "$artifact" && zip -qr "${GITHUB_WORKSPACE}/dist/${name}.zip" .) + (cd "$artifact" && zip -qr "${GITHUB_WORKSPACE}/dist/$(strip_sha "$name").zip" .) fi done + ls -la dist - name: Create release shell: bash env: GH_TOKEN: ${{ github.token }} run: | - ls -la dist - gh release create "build-${GITHUB_RUN_NUMBER}" dist/* \ + set -euo pipefail + tag="build-${GITHUB_RUN_NUMBER}" + base="https://github.com/${GITHUB_REPOSITORY}/releases/download/${tag}" + + cat > notes.md <<EOF + Automatic build of \`${GITHUB_REF_NAME}\` at ${GITHUB_SHA}. + + ## Linux + + Linux packages come as an AppImage (self-contained, needs glibc 2.39 or newer: Ubuntu 24.04, Fedora 40, Debian 13, Arch) and a tar.gz (uses your system libraries, so Qt 6 and the usual libraries must be installed). + + | Build Type | Standard | PGO (Recommended) | Notes | + | --- | --- | --- | --- | + | amd64 | [AppImage](${base}/eglantine-linux-x86_64.AppImage) · [tar.gz](${base}/eglantine-linux-x86_64.tar.gz) | [AppImage](${base}/eglantine-linux-x86_64-pgo.AppImage) · [tar.gz](${base}/eglantine-linux-x86_64-pgo.tar.gz) | Make the AppImage executable (\`chmod +x\`) and run it | + | ARM (aarch64) | [AppImage](${base}/eglantine-linux-aarch64.AppImage) · [tar.gz](${base}/eglantine-linux-aarch64.tar.gz) | [AppImage](${base}/eglantine-linux-aarch64-pgo.AppImage) · [tar.gz](${base}/eglantine-linux-aarch64-pgo.tar.gz) | | + + ## Windows + + Windows packages are in-place zip files: extract and run \`eglantine.exe\`, or \`eden-cli.exe\` from a terminal. + + | Build Type | Standard | PGO (Recommended) | Notes | + | --- | --- | --- | --- | + | amd64 / x86_64 (MSVC) | [MSVC zip](${base}/eglantine-windows-x86_64.zip) | | Use if you run into graphical issues on other builds | + | amd64 / x86_64 (MinGW) | | [PGO zip](${base}/eglantine-windows-x86_64-pgo.zip) | Built with MinGW clang; bundles its own DLLs, no Visual C++ redistributable needed | + + ## macOS + + | Build Type | Standard | PGO (Recommended) | Notes | + | --- | --- | --- | --- | + | arm64 (Apple Silicon) | [zip](${base}/eglantine-macos-arm64.zip) | | macOS 15 or newer. Not notarized: right-click and choose Open the first time, or run \`xattr -dr com.apple.quarantine eglantine.app\`. \`eden-cli\` is inside the app, in \`Contents/MacOS\` | + + The PGO builds are the same programs compiled with profile-guided optimization (clang plus Eden's profile); prefer them when your CPU supports it. + EOF + + gh release create "${tag}" dist/* \ --repo "${GITHUB_REPOSITORY}" \ --target "${GITHUB_SHA}" \ --prerelease \ --title "Eglantine ${GITHUB_REF_NAME} build ${GITHUB_RUN_NUMBER} (${GITHUB_SHA::7})" \ - --notes "Automatic build of ${GITHUB_REF_NAME} at ${GITHUB_SHA}. - - Windows: extract the zip and run eglantine.exe, or eden-cli.exe from a terminal. - Linux (AppImage): make it executable (chmod +x) and run it; it bundles its libraries and needs glibc 2.39 or newer (Ubuntu 24.04, Fedora 40, Debian 13, Arch). - Linux (tar.gz): extract it and run ./eglantine or ./eden-cli; it uses your system libraries, so Qt 6 and the usual libraries must be installed. - The -pgo builds are the same programs compiled with profile-guided optimization (clang plus Eden's profile); prefer them when your CPU supports it. The Windows PGO build is a MinGW build, so it carries its own DLLs and needs no Visual C++ redistributable." + --notes-file notes.md - name: Ping Discord shell: bash |
