Multiplatform build and upload #750
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Multiplatform build and upload | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Release tag" | |
| required: false | |
| type: string | |
| build_android_arm64v8a_release: | |
| description: 'Build Android arm64-v8a Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_android_arm64v8a_debug: | |
| description: 'Build Android arm64-v8a Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_android_armv7a_release: | |
| description: 'Build Android armeabi-v7a Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_android_armv7a_debug: | |
| description: 'Build Android armeabi-v7a Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_ios_release: | |
| description: 'Build iOS Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_ios_debug: | |
| description: 'Build iOS Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_osx_release: | |
| description: 'Build OSX Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_osx_debug: | |
| description: 'Build OSX Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_linux_x86_64_release: | |
| description: 'Build Linux x86_64 Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_linux_x86_64_debug: | |
| description: 'Build Linux x86_64 Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_linux_aarch64_release: | |
| description: 'Build Linux aarch64 Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_linux_aarch64_debug: | |
| description: 'Build Linux aarch64 Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_windows_release: | |
| description: 'Build Windows Release' | |
| required: true | |
| default: true | |
| type: boolean | |
| build_windows_debug: | |
| description: 'Build Windows Debug' | |
| required: true | |
| default: true | |
| type: boolean | |
| env: | |
| GH_TOKEN: ${{ secrets.GNUS_TOKEN_1 }} | |
| jobs: | |
| build: | |
| runs-on: ${{matrix.host}} | |
| container: | |
| image: ${{matrix.container}} | |
| credentials: | |
| username: ${{github.actor}} | |
| password: ${{secrets.GNUS_TOKEN_1}} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: [ Android, iOS, OSX, Linux, Windows ] | |
| build-type: [ Debug, Release ] | |
| abi: [ "" ] | |
| include: | |
| - target: Linux | |
| host: sg-ubuntu-linux | |
| abi: x86_64 | |
| build-type: Debug | |
| container: ghcr.io/geniusventures/debian-bullseye:latest | |
| - target: Linux | |
| host: sg-ubuntu-linux | |
| abi: x86_64 | |
| build-type: Release | |
| container: ghcr.io/geniusventures/debian-bullseye:latest | |
| - target: Linux | |
| host: sg-arm-linux | |
| abi: aarch64 | |
| build-type: Debug | |
| container: ghcr.io/geniusventures/debian-bullseye:latest | |
| - target: Linux | |
| host: sg-arm-linux | |
| abi: aarch64 | |
| build-type: Release | |
| container: ghcr.io/geniusventures/debian-bullseye:latest | |
| - target: Windows | |
| host: SG-WIN11 | |
| - target: OSX | |
| host: gv-OSX-Large | |
| - target: iOS | |
| host: gv-OSX-Large | |
| - target: Android | |
| host: sg-ubuntu-linux | |
| build-type: Release | |
| abi: arm64-v8a | |
| - target: Android | |
| host: sg-ubuntu-linux | |
| build-type: Release | |
| abi: armeabi-v7a | |
| - target: Android | |
| host: sg-ubuntu-linux | |
| build-type: Debug | |
| abi: arm64-v8a | |
| - target: Android | |
| host: sg-ubuntu-linux | |
| build-type: Debug | |
| abi: armeabi-v7a | |
| exclude: | |
| - target: Android | |
| abi: "" | |
| - target: Linux | |
| abi: "" | |
| steps: | |
| - name: Configure Git Bash on Windows | |
| if: ${{ runner.environment == 'self-hosted' && matrix.target == 'Windows' }} | |
| run: | | |
| $gitBinPath = "C:\Program Files\Git\bin" | |
| if (Test-Path $gitBinPath) { | |
| Add-Content -Path $env:GITHUB_PATH -Value $gitBinPath | |
| $env:PATH = "$gitBinPath;$env:PATH" | |
| } | |
| Write-Output "Git Bash configured for bash shell commands" | |
| $bashLocation = (Get-Command bash.exe -ErrorAction SilentlyContinue).Source | |
| if ($bashLocation) { | |
| Write-Output "Bash location: $bashLocation" | |
| } else { | |
| Write-Output "WARNING: bash.exe not found in PATH" | |
| } | |
| - name: Check if build should run | |
| if: ${{ github.event_name == 'workflow_dispatch' }} | |
| shell: bash | |
| run: | | |
| SHOULD_RUN="true" | |
| # Only check inputs on workflow_dispatch events | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| case '${{matrix.target}}-${{matrix.abi}}-${{ matrix.build-type }}' in | |
| Android-arm64-v8a-Release) | |
| if [ '${{ inputs.build_android_arm64v8a_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Android-arm64-v8a-Debug) | |
| if [ '${{ inputs.build_android_arm64v8a_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Android-armeabi-v7a-Release) | |
| if [ '${{ inputs.build_android_armv7a_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Android-armeabi-v7a-Debug) | |
| if [ '${{ inputs.build_android_armv7a_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| iOS-*-Release) | |
| if [ '${{ inputs.build_ios_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| iOS-*-Debug) | |
| if [ '${{ inputs.build_ios_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| OSX-*-Release) | |
| if [ '${{ inputs.build_osx_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| OSX-*-Debug) | |
| if [ '${{ inputs.build_osx_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Linux-x86_64-Release) | |
| if [ '${{ inputs.build_linux_x86_64_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Linux-x86_64-Debug) | |
| if [ '${{ inputs.build_linux_x86_64_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Linux-aarch64-Release) | |
| if [ '${{ inputs.build_linux_aarch64_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Linux-aarch64-Debug) | |
| if [ '${{ inputs.build_linux_aarch64_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Windows-*-Release) | |
| if [ '${{ inputs.build_windows_release }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| Windows-*-Debug) | |
| if [ '${{ inputs.build_windows_debug }}' != 'true' ]; then SHOULD_RUN="false"; fi | |
| ;; | |
| esac | |
| fi | |
| if [ "$SHOULD_RUN" == "false" ]; then | |
| echo "Skipping build for ${{ matrix.target }} ${{ matrix.abi }} ${{ matrix.build-type }}" | |
| exit 78 | |
| fi | |
| - name: Clean workspace (self-hosted runners) | |
| if: ${{ runner.environment == 'self-hosted' }} | |
| working-directory: ${{runner.workspace}} | |
| run: | | |
| echo "=== PRE-CLEANUP DEBUG ===" | |
| echo "Current working directory: $(pwd)" | |
| echo "Runner workspace: ${{runner.workspace}}" | |
| echo "GitHub workspace: ${{github.workspace}}" | |
| # Use sudo on Linux to handle root-owned files left by container jobs | |
| SUDO="" | |
| if [ "$(uname)" = "Linux" ]; then | |
| SUDO="sudo" | |
| fi | |
| echo "=== CLEANUP ARTIFACTS ===" | |
| # Clean contents of thirdparty directory but keep the directory itself | |
| if [ -d "thirdparty" ]; then | |
| echo "Cleaning thirdparty directory contents..." | |
| $SUDO rm -rf thirdparty/* thirdparty/.* 2>/dev/null || true | |
| echo "thirdparty directory cleaned (kept the directory)" | |
| fi | |
| echo "=== POST-CLEANUP DEBUG ===" | |
| echo "Runner workspace contents:" | |
| ls -la | |
| if [ -d "thirdparty" ]; then | |
| echo "thirdparty directory exists and contains:" | |
| ls -la thirdparty/ 2>/dev/null || echo " (empty)" | |
| fi | |
| shell: bash | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: "recursive" | |
| - name: Configure Linux host | |
| if: ${{ runner.os == 'Linux'}} | |
| run: | | |
| sudo update-alternatives --install /usr/bin/cc cc $(which clang) 100 | |
| sudo update-alternatives --install /usr/bin/c++ c++ $(which clang++) 100 | |
| sudo update-alternatives --set cc $(which clang) | |
| sudo update-alternatives --set c++ $(which clang++) | |
| sudo apt install libvulkan-dev ninja-build -y | |
| echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV | |
| - name: Configure macOS host | |
| if: ${{ runner.os == 'macOS'}} | |
| run: | | |
| brew install ninja bash gnu-tar | |
| # Ensure GNU tar is first in PATH | |
| if [ -d "/opt/homebrew/opt/gnu-tar/libexec/gnubin" ]; then | |
| echo "PATH=/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV | |
| echo "Using GNU tar from /opt/homebrew" | |
| elif [ -d "/usr/local/opt/gnu-tar/libexec/gnubin" ]; then | |
| echo "PATH=/usr/local/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV | |
| echo "Using GNU tar from /usr/local" | |
| else | |
| echo "WARNING: GNU tar installation not found in expected locations" | |
| echo "Available tar: $(which tar)" | |
| fi | |
| echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV | |
| - name: Add Darwin toolchain | |
| if: ${{ matrix.target == 'OSX'}} | |
| run: rustup target add x86_64-apple-darwin | |
| - name: Add iOS toolchain | |
| if: ${{ matrix.target == 'iOS' }} | |
| run: | | |
| rustup toolchain install nightly-aarch64-apple-darwin | |
| rustup component add rust-src --toolchain nightly-aarch64-apple-darwin | |
| rustup target add aarch64-apple-ios | |
| - name: Add Android toolchain | |
| if: ${{ matrix.target == 'Android' }} | |
| run: | | |
| NDK_VERSION="r27b" | |
| NDK_DIR="$HOME/android-ndk-$NDK_VERSION" | |
| if [ ! -d "$NDK_DIR" ]; then | |
| echo "Downloading Android NDK..." | |
| wget https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux.zip -O ndk.zip | |
| unzip -o ndk.zip -d $HOME | |
| rm ndk.zip | |
| else | |
| echo "Android NDK already exists at $NDK_DIR, skipping download" | |
| fi | |
| echo "ANDROID_NDK_HOME=$NDK_DIR" >> $GITHUB_ENV | |
| rustup target add aarch64-linux-android | |
| rustup target add armv7-linux-androideabi | |
| - name: Install bindgen | |
| run: cargo install cbindgen | |
| - name: Add wasm Rust target | |
| run: rustup target add wasm32-unknown-emscripten | |
| - name: Set build directory | |
| run: | | |
| if [ '${{matrix.abi}}' ]; then | |
| BUILD_DIRECTORY=build/${{matrix.target}}/${{matrix.build-type}}/${{matrix.abi}} | |
| else | |
| BUILD_DIRECTORY=build/${{matrix.target}}/${{matrix.build-type}} | |
| fi | |
| echo "BUILD_DIRECTORY=$BUILD_DIRECTORY" >> $GITHUB_ENV | |
| shell: bash | |
| - name: Configure CMake for Mac | |
| if: ${{ matrix.target == 'OSX'}} | |
| run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=MAC_UNIVERSAL | |
| - name: Configure CMake for iOS | |
| if: ${{ matrix.target == 'iOS'}} | |
| run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DPLATFORM=OS64 | |
| - name: Configure CMake for Android | |
| if: ${{ matrix.target == 'Android'}} | |
| run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} -DANDROID_ABI=${{matrix.abi}} | |
| - name: Configure CMake for Windows | |
| if: ${{ matrix.target == 'Windows' }} | |
| run: cmake -S build/${{matrix.target}} -B $env:BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} | |
| - name: Configure CMake for Linux | |
| if: ${{ matrix.target == 'Linux' }} | |
| run: cmake -S build/${{matrix.target}} -B $BUILD_DIRECTORY -DCMAKE_BUILD_TYPE=${{matrix.build-type}} | |
| - name: Build thirdparty | |
| working-directory: ${{env.BUILD_DIRECTORY}} | |
| run: cmake --build . --config ${{matrix.build-type}} -j | |
| - name: Compress directories | |
| if: github.ref_name == 'main' || github.ref_name == 'develop' | |
| working-directory: ${{env.BUILD_DIRECTORY}} | |
| shell: bash | |
| run: | | |
| if [ '${{matrix.abi}}' ]; then | |
| FILE_NAME="${{matrix.target}}-${{matrix.abi}}-${{matrix.build-type}}.tar.gz" | |
| else | |
| FILE_NAME="${{matrix.target}}-${{matrix.build-type}}.tar.gz" | |
| fi | |
| echo "FILE_NAME=$FILE_NAME" >> $GITHUB_ENV | |
| tar --no-wildcards-match-slash --exclude='./*/src' --exclude='./*/tmp' --transform='s|^\.|${{env.BUILD_DIRECTORY}}|g' -czf $FILE_NAME ./*/ | |
| - name: Set release tag | |
| shell: bash | |
| run: | | |
| if ${{ github.event_name == 'workflow_dispatch' }} && [ '${{ github.event.inputs.tag }}' ]; then | |
| RELEASE_TAG="${{ github.event.inputs.tag }}" | |
| IS_TAG_RELEASE="true" | |
| else | |
| if [ '${{matrix.abi}}' ]; then | |
| RELEASE_TAG="${{ matrix.target }}-${{matrix.abi}}-${{ github.ref_name }}-${{ matrix.build-type }}" | |
| else | |
| RELEASE_TAG="${{ matrix.target }}-${{ github.ref_name }}-${{ matrix.build-type }}" | |
| fi | |
| IS_TAG_RELEASE="false" | |
| fi | |
| echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV | |
| echo "IS_TAG_RELEASE=$IS_TAG_RELEASE" >> $GITHUB_ENV | |
| - name: Create release tag | |
| if: github.ref_name == 'main' || github.ref_name == 'develop' | |
| shell: bash | |
| id: create-release-tag | |
| run: | | |
| echo "Checking if release $RELEASE_TAG exists..." | |
| if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then | |
| if [ "$IS_TAG_RELEASE" == "false" ]; then | |
| echo "Deleting existing release/tag $RELEASE_TAG..." | |
| gh release delete "$RELEASE_TAG" --yes || true | |
| git push origin ":refs/tags/$RELEASE_TAG" || true | |
| git tag -d "$RELEASE_TAG" || true | |
| fi | |
| fi | |
| echo "Creating new tag $RELEASE_TAG..." | |
| git tag -f "$RELEASE_TAG" "${{ github.sha }}" | |
| git push origin "$RELEASE_TAG" --force | |
| echo "Creating GitHub release $RELEASE_TAG..." | |
| gh release create "$RELEASE_TAG" \ | |
| --target "${{ github.sha }}" \ | |
| -t "${{ matrix.target }} ${{ github.ref_name }} ${{ matrix.build-type }} build" \ | |
| -n "Branch: ${{ github.ref_name }} | SHA: ${{ github.sha }}" \ | |
| $( [ "$IS_TAG_RELEASE" = "true" ] && echo "" || echo "--prerelease" ) | |
| - name: Upload file | |
| if: github.ref_name == 'main' || github.ref_name == 'develop' | |
| working-directory: ${{env.BUILD_DIRECTORY}} | |
| run: gh release upload ${{env.RELEASE_TAG}} ${{env.FILE_NAME}} --clobber |