Fix six things in the native heads (#846) #84
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: Build native | |
| # Produces the diffengine_viewer binaries committed under | |
| # src/DiffEngineViewer.{Linux,Mac}/runtimes/{rid}/native, in the head that loads them. There is no | |
| # Windows equivalent: that head renders with WinForms. | |
| # | |
| # They are committed rather than built during a normal build so that a plain | |
| # `dotnet build src --configuration Release` produces a shippable package on any machine, and | |
| # contributors never need a C++ toolchain. Run this whenever native/ changes. | |
| on: | |
| push: | |
| paths: | |
| - 'native/**' | |
| - '.github/workflows/build-native.yml' | |
| pull_request: | |
| paths: | |
| - 'native/**' | |
| workflow_dispatch: | |
| inputs: | |
| commit: | |
| description: 'Open a PR with the rebuilt binaries' | |
| type: boolean | |
| default: true | |
| concurrency: | |
| group: build-native-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build: | |
| name: ${{ matrix.rid }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # No Windows entries. That head renders with WinForms and loads no native library. | |
| - rid: linux-x64 | |
| os: ubuntu-24.04 | |
| - rid: linux-arm64 | |
| os: ubuntu-24.04-arm | |
| # One universal binary covers both macOS RIDs; it is copied into each below. | |
| - rid: osx | |
| os: macos-14 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install build dependencies | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| cmake ninja-build \ | |
| libx11-dev libxrandr-dev libxi-dev libxcursor-dev libxinerama-dev \ | |
| libgl1-mesa-dev libglu1-mesa-dev libwayland-dev libxkbcommon-dev | |
| - name: Configure | |
| if: matrix.rid != 'osx' | |
| run: cmake -S native -B build -G Ninja -DCMAKE_BUILD_TYPE=Release | |
| - name: Build | |
| if: matrix.rid != 'osx' | |
| run: cmake --build build --config Release | |
| # macOS draws with AppKit and Core Text rather than raylib and ImGui, so it is a Swift | |
| # package rather than a CMake project. Both --arch flags in one invocation produce a | |
| # universal binary, so there is no separate lipo step. | |
| # | |
| # Nothing of the Swift runtime is shipped: it has been part of macOS since 10.14.4, which is | |
| # why this dylib is a fraction of the size of the one it replaced. | |
| - name: Build | |
| if: matrix.rid == 'osx' | |
| run: swift build -c release --arch arm64 --arch x86_64 --package-path native/swift | |
| - name: Collect | |
| shell: bash | |
| run: | | |
| # Laid out as src/{head}/runtimes/{rid}/native, so the propose job below can merge every | |
| # artifact straight into src and the binaries land in the head that loads them. | |
| collect() { | |
| mkdir -p "artifacts/$1/runtimes/$2/native" | |
| cp "$3" "artifacts/$1/runtimes/$2/native/" | |
| } | |
| case "${{ matrix.rid }}" in | |
| linux-*) | |
| strip build/libdiffengine_viewer.so | |
| collect DiffEngineViewer.Linux "${{ matrix.rid }}" build/libdiffengine_viewer.so | |
| ;; | |
| osx) | |
| # swift build leaves a per architecture dylib in more than one place, so taking the | |
| # first one found gives a single slice binary that loads on half the Macs in the | |
| # world. Every candidate is checked, and if none is already universal they are | |
| # merged, so the only thing that can be collected is a fat binary. | |
| # The dSYM contains a DWARF file of the same name which is also universal, so the | |
| # arch check below would happily accept it and ship debug symbols as the library. | |
| candidates=$(find native/swift/.build -name libdiffengine_viewer.dylib -not -path '*.dSYM/*') | |
| if [ -z "$candidates" ]; then | |
| echo "::error::swift build produced no libdiffengine_viewer.dylib" | |
| exit 1 | |
| fi | |
| echo "$candidates" | while read -r candidate; do | |
| echo "$candidate: $(lipo -archs "$candidate" 2>/dev/null)" | |
| done | |
| dylib="" | |
| for candidate in $candidates; do | |
| archs=$(lipo -archs "$candidate" 2>/dev/null || echo "") | |
| if [[ "$archs" == *x86_64* && "$archs" == *arm64* ]]; then | |
| dylib="$candidate" | |
| break | |
| fi | |
| done | |
| if [ -z "$dylib" ]; then | |
| dylib=universal/libdiffengine_viewer.dylib | |
| mkdir -p universal | |
| # shellcheck disable=SC2086 | |
| lipo -create $candidates -output "$dylib" | |
| fi | |
| archs=$(lipo -archs "$dylib") | |
| echo "collecting $dylib: $archs" | |
| for arch in x86_64 arm64; do | |
| case " $archs " in | |
| *" $arch "*) ;; | |
| *) echo "::error::$dylib is missing the $arch slice"; exit 1 ;; | |
| esac | |
| done | |
| strip -x "$dylib" | |
| # The dylib is universal, so both macOS RIDs get the same file. | |
| collect DiffEngineViewer.Mac osx-x64 "$dylib" | |
| collect DiffEngineViewer.Mac osx-arm64 "$dylib" | |
| ;; | |
| esac | |
| ls -lhR artifacts | |
| - name: Upload | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-${{ matrix.rid }} | |
| path: artifacts/ | |
| retention-days: 7 | |
| propose: | |
| name: propose update | |
| needs: build | |
| # Also on push, not just manual dispatch. workflow_dispatch does not appear in the Actions UI | |
| # until the workflow is on the default branch, so on a feature branch a push is the only way | |
| # to trigger this, and leaving the binaries as bare artifacts to copy by hand is worse. | |
| # | |
| # Branches only. Never on pull_request, which would mean opening a PR from a PR, and never on | |
| # a tag: a tag checkout is a detached HEAD with no base branch to target, and proposing a | |
| # binaries PR against a release tag is meaningless anyway. | |
| if: >- | |
| github.event_name != 'pull_request' && | |
| startsWith(github.ref, 'refs/heads/') && | |
| (github.event_name != 'workflow_dispatch' || inputs.commit) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: native-* | |
| merge-multiple: true | |
| path: src | |
| - name: Show what changed | |
| run: | | |
| ls -lhR src/DiffEngineViewer.Linux/runtimes src/DiffEngineViewer.Mac/runtimes | |
| git status --short | |
| # A PR rather than a direct push: these are binaries, so the diff is not reviewable and the | |
| # change deserves an explicit approval. | |
| - name: Open pull request | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| # Scoped to the triggering branch, which is also the base, so a rebuild on a feature | |
| # branch does not collide with one on main. | |
| branch: native-binaries-${{ github.ref_name }} | |
| title: 'Rebuild native renderer binaries' | |
| commit-message: 'Rebuild native renderer binaries' | |
| body: | | |
| Rebuilt `diffengine_viewer` from `native/` for the four RIDs that load one. | |
| Windows is not among them: that head renders with WinForms. | |
| Produced by the `build-native` workflow from ${{ github.sha }}. | |
| add-paths: | | |
| src/DiffEngineViewer.Linux/runtimes | |
| src/DiffEngineViewer.Mac/runtimes |