fix(ci-windows): bundle ffmpeg DLLs from lib/ + drop flaky MSYS2 setup #163
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 + Validate | |
| on: | |
| push: | |
| branches: ['**'] | |
| tags: ['v*'] | |
| pull_request: | |
| branches: [main] | |
| env: | |
| BUILD_TYPE: Release | |
| jobs: | |
| build-macos: | |
| runs-on: macos-14 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup CMake | |
| uses: lukka/get-cmake@latest | |
| - name: Build universal OpenSSL | |
| run: | | |
| OPENSSL_VER=3.4.1 | |
| curl -sL "https://github.com/openssl/openssl/releases/download/openssl-${OPENSSL_VER}/openssl-${OPENSSL_VER}.tar.gz" | tar xz | |
| cd "openssl-${OPENSSL_VER}" | |
| # arm64 | |
| ./Configure darwin64-arm64-cc --prefix="$GITHUB_WORKSPACE/openssl-arm64" no-shared no-tests | |
| make -j$(sysctl -n hw.ncpu) && make install_sw && make clean | |
| # x86_64 | |
| ./Configure darwin64-x86_64-cc --prefix="$GITHUB_WORKSPACE/openssl-x86_64" no-shared no-tests | |
| make -j$(sysctl -n hw.ncpu) && make install_sw | |
| # lipo into universal | |
| mkdir -p "$GITHUB_WORKSPACE/openssl-universal/lib" | |
| cp -r "$GITHUB_WORKSPACE/openssl-arm64/include" "$GITHUB_WORKSPACE/openssl-universal/" | |
| lipo -create "$GITHUB_WORKSPACE/openssl-arm64/lib/libcrypto.a" \ | |
| "$GITHUB_WORKSPACE/openssl-x86_64/lib/libcrypto.a" \ | |
| -output "$GITHUB_WORKSPACE/openssl-universal/lib/libcrypto.a" | |
| lipo -create "$GITHUB_WORKSPACE/openssl-arm64/lib/libssl.a" \ | |
| "$GITHUB_WORKSPACE/openssl-x86_64/lib/libssl.a" \ | |
| -output "$GITHUB_WORKSPACE/openssl-universal/lib/libssl.a" | |
| lipo -info "$GITHUB_WORKSPACE/openssl-universal/lib/libcrypto.a" | |
| - name: Verify LGPL discipline (vendored trees in libs/ffmpeg/) | |
| # Iterate every populated libs/ffmpeg/<platform>/ tree (both arches | |
| # of macOS are now committed) and assert no libx264 strings + clean | |
| # otool/ldd linkage. Exits 1 on any contamination. | |
| # The "Vendor LGPL ffmpeg" rebuild-from-source step that used to run | |
| # here was removed 2026-05-19 — libs/ffmpeg/macos-arm64/ and | |
| # libs/ffmpeg/macos-x86_64/ are both bundled in the repo, so a | |
| # 15-25 min CI rebuild on every push became a no-op git checkout. | |
| # Run scripts/build_ffmpeg_lgpl.sh manually when bumping ffmpeg or | |
| # openh264 version and commit the refreshed trees. | |
| run: bash scripts/verify_ffmpeg_lgpl.sh | |
| - name: Configure CMake (universal — arm64 + x86_64) | |
| # Universal mac build: cmake/ffmpeg.cmake detects the multi-arch | |
| # CMAKE_OSX_ARCHITECTURES and lipo's libs/ffmpeg/macos-{arm64,x86_64}/ | |
| # dylibs into a universal tree at ${CMAKE_BINARY_DIR}/ffmpeg-universal/ | |
| # at configure time. JUCE/CMake compiles each .o twice + the linker | |
| # produces fat artifacts. Output runs natively on Apple Silicon AND | |
| # Intel Macs. | |
| # JAMWIDE_BUILD_TESTS + JAMWIDE_VIDEO_SPIKE pulled the test executables | |
| # (incl. test_flac_codec which has a pre-existing WDL_VORBIS_INTERFACE_ONLY | |
| # guard gap in wdl/vorbisencdec.h that caused the compile to fail). | |
| run: | | |
| cmake -B build \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ | |
| -DJAMWIDE_BUILD_JUCE=ON \ | |
| -DJAMWIDE_BUILD_CLAP=OFF \ | |
| -DJAMWIDE_DEV_BUILD=OFF \ | |
| -DOPENSSL_ROOT_DIR="$GITHUB_WORKSPACE/openssl-universal" | |
| - name: Build | |
| run: cmake --build build --config Release -j $(sysctl -n hw.ncpu) | |
| - name: Verify artifacts | |
| run: | | |
| echo "=== Build artifacts ===" | |
| ls -la "build/JamWideJuce_artefacts/Release/VST3/JamWide.vst3/" || echo "VST3 not found" | |
| ls -la "build/JamWideJuce_artefacts/Release/AU/JamWide.component/" || echo "AU not found" | |
| ls -la "build/JamWideJuce_artefacts/Release/CLAP/JamWide.clap/" || echo "CLAP not found" | |
| ls -la "build/JamWideJuce_artefacts/Release/Standalone/JamWide.app/" || echo "Standalone not found" | |
| - name: Download pluginval | |
| run: | | |
| curl -L https://github.com/Tracktion/pluginval/releases/latest/download/pluginval_macOS.zip -o pluginval.zip | |
| unzip pluginval.zip | |
| - name: Force AU re-scan | |
| run: killall -9 AudioComponentRegistrar 2>/dev/null || true | |
| - name: Validate VST3 | |
| run: | | |
| ./pluginval.app/Contents/MacOS/pluginval \ | |
| --validate-in-process \ | |
| --strictness-level 5 \ | |
| --timeout-ms 120000 \ | |
| --validate "build/JamWideJuce_artefacts/Release/VST3/JamWide.vst3" | |
| - name: Validate AU | |
| continue-on-error: true | |
| run: | | |
| ./pluginval.app/Contents/MacOS/pluginval \ | |
| --validate-in-process \ | |
| --strictness-level 5 \ | |
| --timeout-ms 120000 \ | |
| --validate "build/JamWideJuce_artefacts/Release/AU/JamWide.component" | |
| - name: Validate Standalone | |
| continue-on-error: true | |
| run: | | |
| ./pluginval.app/Contents/MacOS/pluginval \ | |
| --validate-in-process \ | |
| --strictness-level 5 \ | |
| --timeout-ms 120000 \ | |
| --validate "build/JamWideJuce_artefacts/Release/Standalone/JamWide.app" | |
| - name: Import signing certificate | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| CERTIFICATE_P12: ${{ secrets.DEVELOPER_ID_P12 }} | |
| CERTIFICATE_PASSWORD: ${{ secrets.DEVELOPER_ID_P12_PASSWORD }} | |
| run: | | |
| KEYCHAIN_PATH=$RUNNER_TEMP/signing.keychain-db | |
| KEYCHAIN_PASSWORD=$(openssl rand -hex 16) | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| echo "$CERTIFICATE_P12" | base64 --decode > "$RUNNER_TEMP/cert.p12" | |
| security import "$RUNNER_TEMP/cert.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') | |
| rm "$RUNNER_TEMP/cert.p12" | |
| - name: Sign and notarize bundles | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| NOTARIZE_KEY_ID: ${{ secrets.NOTARIZE_KEY_ID }} | |
| NOTARIZE_ISSUER_ID: ${{ secrets.NOTARIZE_ISSUER_ID }} | |
| NOTARIZE_KEY_PATH: ${{ runner.temp }}/AuthKey.p8 | |
| NOTARIZE_API_KEY_B64: ${{ secrets.NOTARIZE_API_KEY_P8 }} | |
| run: | | |
| echo "$NOTARIZE_API_KEY_B64" | base64 --decode > "$NOTARIZE_KEY_PATH" | |
| ./scripts/notarize.sh build/JamWideJuce_artefacts/Release | |
| rm -f "$NOTARIZE_KEY_PATH" | |
| - name: Package artifacts | |
| run: | | |
| mkdir -p staging | |
| cp -r "build/JamWideJuce_artefacts/Release/VST3/JamWide.vst3" staging/ | |
| cp -r "build/JamWideJuce_artefacts/Release/AU/JamWide.component" staging/ | |
| cp -r "build/JamWideJuce_artefacts/Release/CLAP/JamWide.clap" staging/ | |
| cp -r "build/JamWideJuce_artefacts/Release/Standalone/JamWide.app" staging/ | |
| cd staging && tar czf ../JamWide-macOS.tar.gz . | |
| - name: Upload macOS artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: JamWide-macOS | |
| path: JamWide-macOS.tar.gz | |
| retention-days: 30 | |
| build-windows: | |
| # Enabled 2026-05-18 (Phase 22 UAT exit ramp): the MSYS2 ffmpeg-vendoring | |
| # script + windows-x86_64 leg has been written since Phase 14.3 but never | |
| # exercised on a real CI run. This is the first attempt; Phase 23's full | |
| # signtool + dumpbin /dependents gate is still owed but we ship an | |
| # unsigned Windows-x86_64 beta artifact for early testers in the meantime. | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup CMake | |
| uses: lukka/get-cmake@latest | |
| - name: Verify LGPL discipline (vendored trees in libs/ffmpeg/) | |
| # Iterates every populated libs/ffmpeg/<platform>/ tree (Windows | |
| # vendored as of this commit) and asserts no libx264 strings + clean | |
| # PE-import dependency check. Same gate that the mac CI runs against | |
| # the bundled trees. | |
| # The "Vendor LGPL ffmpeg" rebuild-from-source step that used to run | |
| # here was removed once libs/ffmpeg/windows-x86_64/ landed bundled | |
| # in the repo — saves 15-25 min/CI run and eliminates the gendef/ | |
| # dlltool/lib generation toolchain-rot surface that took multiple | |
| # iterations to get green. Run scripts/build_ffmpeg_lgpl.sh manually | |
| # under MSYS2 when bumping ffmpeg or openh264 version, then commit | |
| # the refreshed tree. | |
| # Runs under Git Bash (shipped on windows-latest by default — has | |
| # bash + binutils strings). Dropped the previous setup-msys2 step | |
| # in beta.20.9 after pacman -Syuu kept timing out against | |
| # mirror.accum.se, breaking the tag CI for a transient mirror | |
| # issue unrelated to our actual build. | |
| shell: bash | |
| run: bash scripts/verify_ffmpeg_lgpl.sh | |
| - name: Configure CMake | |
| run: | | |
| cmake -B build ` | |
| -G "Visual Studio 17 2022" ` | |
| -A x64 ` | |
| -DJAMWIDE_BUILD_JUCE=ON ` | |
| -DJAMWIDE_BUILD_CLAP=OFF ` | |
| -DJAMWIDE_DEV_BUILD=OFF | |
| - name: Build | |
| run: cmake --build build --config Release | |
| - name: Verify artifacts | |
| shell: pwsh | |
| run: | | |
| Write-Host "=== Build artifacts ===" | |
| Get-ChildItem -Path "build/JamWideJuce_artefacts" -Recurse -Include "*.vst3","*.clap" -Directory | Select-Object FullName | |
| - name: Download pluginval | |
| shell: pwsh | |
| run: | | |
| Invoke-WebRequest -Uri "https://github.com/Tracktion/pluginval/releases/latest/download/pluginval_Windows.zip" -OutFile pluginval.zip | |
| Expand-Archive -Path pluginval.zip -DestinationPath pluginval | |
| - name: Validate VST3 | |
| run: | | |
| pluginval\pluginval.exe --validate-in-process --strictness-level 5 --timeout-ms 120000 --validate "build\JamWideJuce_artefacts\Release\VST3\JamWide.vst3" | |
| - name: Stage artifacts | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Path staging -Force | |
| # VST3: single-file bundle (extract DLL from package directory) | |
| Copy-Item "build/JamWideJuce_artefacts/Release/VST3/JamWide.vst3/Contents/x86_64-win/JamWide.vst3" "staging/JamWide.vst3" | |
| # CLAP: single-file bundle | |
| Copy-Item "build/JamWideJuce_artefacts/Release/CLAP/JamWide.clap" "staging/JamWide.clap" | |
| # Standalone | |
| Copy-Item "build/JamWideJuce_artefacts/Release/Standalone/JamWide.exe" "staging/JamWide.exe" | |
| # Vendored ffmpeg DLLs (LGPL) — required runtime deps for video | |
| # encode/decode. Phase 23-02 owns proper Windows install layout; | |
| # for the beta we just colocate the DLLs next to the standalone + | |
| # plugins so Windows' DLL search resolves them. Per memory | |
| # `project_release_packaging`: Windows uses zip (not tar.gz). | |
| # The DLLs live in libs/ffmpeg/windows-x86_64/lib/ (the same dir | |
| # as the MSVC .lib import libraries — MinGW autotools dropped | |
| # them all under lib/ regardless of .dll vs .lib). The previous | |
| # path "libs/ffmpeg/windows-x86_64/bin/" did not exist on the | |
| # runner and the Test-Path soft-check silently skipped the copy, | |
| # shipping v1.1-beta.20.8 Windows zip without any ffmpeg DLLs | |
| # — that beta launch-crashed on Windows for the same reason | |
| # the macOS .app did (missing runtime ffmpeg, just a different | |
| # OS' dynamic loader complaining). | |
| $ffmpegDlls = Get-ChildItem "libs/ffmpeg/windows-x86_64/lib/*.dll" -ErrorAction SilentlyContinue | |
| if ($ffmpegDlls) { | |
| Copy-Item $ffmpegDlls "staging/" | |
| Write-Host "Staged $($ffmpegDlls.Count) ffmpeg DLL(s)" | |
| } else { | |
| Write-Error "No ffmpeg DLLs found under libs/ffmpeg/windows-x86_64/lib/ — packaging would ship a broken Windows zip" | |
| exit 1 | |
| } | |
| - name: Package Windows zip | |
| shell: pwsh | |
| run: | | |
| # Per memory `project_release_packaging`: Windows uses zip (not | |
| # tar.gz). PowerShell's Compress-Archive is native and preserves | |
| # the flat layout the staging step produced. | |
| Compress-Archive -Path "staging/*" -DestinationPath "JamWide-Windows.zip" -Force | |
| - name: Upload Windows artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: JamWide-Windows | |
| path: JamWide-Windows.zip | |
| retention-days: 30 | |
| build-linux: | |
| # Disabled for v1.3 betas — Phase 19's camera-capture code uses | |
| # juce::CameraDevice unconditionally, but juce_video has no | |
| # juce_CameraDevice_linux.h (Linux capture deferred per memory | |
| # 'project_jamtaba_video_port': Linux is receive-only v1, V4L2 | |
| # wrapper is post-v1 Item K). Re-enable once a Linux capture path | |
| # (or conditional compile around the camera code) lands. Same one-line | |
| # flip as build-windows. | |
| if: ${{ false }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential cmake pkg-config \ | |
| nasm \ | |
| libasound2-dev \ | |
| libjack-jackd2-dev \ | |
| libfreetype-dev \ | |
| libx11-dev \ | |
| libxrandr-dev \ | |
| libxinerama-dev \ | |
| libxcursor-dev \ | |
| libxcomposite-dev \ | |
| libgl1-mesa-dev \ | |
| libcurl4-openssl-dev \ | |
| libwebkit2gtk-4.1-dev \ | |
| libssl-dev | |
| - name: Vendor LGPL ffmpeg | |
| # Phase 14.3-01: produce libs/ffmpeg/linux-x86_64/ on the CI runner via | |
| # scripts/build_ffmpeg_lgpl.sh. The script's OS+ARCH dispatch picks the | |
| # Linux-x86_64 leg (Cisco openh264 v2.1.1 prebuilt + ffmpeg LGPL from | |
| # source). All inputs are static; no untrusted github event data flows | |
| # into shell. | |
| run: bash scripts/build_ffmpeg_lgpl.sh | |
| - name: Verify LGPL discipline | |
| run: bash scripts/verify_ffmpeg_lgpl.sh | |
| - name: Configure CMake | |
| run: | | |
| cmake -B build \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DJAMWIDE_BUILD_JUCE=ON \ | |
| -DJAMWIDE_BUILD_CLAP=OFF \ | |
| -DJAMWIDE_DEV_BUILD=OFF | |
| - name: Build | |
| run: cmake --build build --config Release -j $(nproc) | |
| - name: Verify artifacts | |
| run: | | |
| echo "=== Build artifacts ===" | |
| find build/JamWideJuce_artefacts -name "*.vst3" -o -name "*.clap" -o -name "*.so" | head -20 | |
| - name: Download pluginval | |
| run: | | |
| curl -L https://github.com/Tracktion/pluginval/releases/latest/download/pluginval_Linux.zip -o pluginval.zip | |
| unzip pluginval.zip | |
| chmod +x pluginval | |
| - name: Validate VST3 | |
| continue-on-error: true | |
| run: | | |
| ./pluginval \ | |
| --validate-in-process \ | |
| --strictness-level 5 \ | |
| --timeout-ms 120000 \ | |
| --validate "build/JamWideJuce_artefacts/Release/VST3/JamWide.vst3" | |
| - name: Package artifacts | |
| run: | | |
| mkdir -p staging | |
| cp -r "build/JamWideJuce_artefacts/Release/VST3/JamWide.vst3" staging/ | |
| cp "build/JamWideJuce_artefacts/Release/CLAP/JamWide.clap" staging/ | |
| cp "build/JamWideJuce_artefacts/Release/Standalone/JamWide" staging/ | |
| cd staging && tar czf ../JamWide-Linux.tar.gz . | |
| - name: Upload Linux artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: JamWide-Linux | |
| path: JamWide-Linux.tar.gz | |
| retention-days: 30 | |
| release: | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| # macOS universal + Windows x64 both shipping as of v1.1-beta.20.8 | |
| # (50b7678 — bundled libs/ffmpeg/windows-x86_64/ with MSVC .lib import | |
| # libraries generated via gendef + dlltool). Linux still owes the | |
| # JUCE_LINUX camera-code conditional; queued for v1.1-beta.20.9. | |
| needs: [build-macos, build-windows] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Prepare release artifacts | |
| run: | | |
| # macOS universal uses tar.gz (preserves Unix permissions per memory | |
| # `project_release_packaging`); Windows uses zip. Linux still | |
| # deferred (camera-code conditional queued). | |
| cp artifacts/JamWide-macOS/JamWide-macOS.tar.gz . | |
| cp artifacts/JamWide-Windows/JamWide-Windows.zip . | |
| - name: Create or update release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG_NAME: ${{ github.ref_name }} | |
| run: | | |
| PRERELEASE_FLAG="" | |
| if echo "$TAG_NAME" | grep -qE "beta|alpha|rc"; then | |
| PRERELEASE_FLAG="--prerelease" | |
| fi | |
| if gh release view "$TAG_NAME" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then | |
| echo "Release $TAG_NAME already exists — uploading assets" | |
| gh release upload "$TAG_NAME" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --clobber \ | |
| JamWide-macOS.tar.gz \ | |
| JamWide-Windows.zip | |
| else | |
| gh release create "$TAG_NAME" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "$TAG_NAME" \ | |
| --generate-notes \ | |
| $PRERELEASE_FLAG \ | |
| JamWide-macOS.tar.gz \ | |
| JamWide-Windows.zip | |
| fi |