Updated scripts for Windows build #70
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 revo-lib with OBS 32.x | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: [ main ] | |
| jobs: | |
| build-macos: | |
| name: Build (macOS) | |
| runs-on: macos-15-intel | |
| env: | |
| MACOSX_DEPLOYMENT_TARGET: "13.0" | |
| CMAKE_OSX_DEPLOYMENT_TARGET: "13.0" | |
| RUST_BACKTRACE: "1" | |
| # build.rs używa tego jako ref (domyślnie 32.1.0-rc1 jeśli brak) | |
| REVO_OBS_REF: "32.1.0-rc1" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install dependencies | |
| run: | | |
| brew update | |
| brew install simde ffmpeg mbedtls speexdsp uthash jansson cmake ninja pkg-config | |
| - name: Build (revo-lib) + build.rs builds OBS | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --release | |
| - name: Package prebuilt libobs artifact (layout compatible with REVO_PREBUILT_LIBOBS_DIR) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ARCH=$(uname -m) | |
| STAGING="libobs-prebuilt-macos-${ARCH}" | |
| OBS_SRC="obs-libobs/obs-studio" | |
| BUILD_DIR="${OBS_SRC}/build-headless" | |
| INSTALL_PREFIX="${BUILD_DIR}/install" | |
| mkdir -p "${STAGING}/framework" | |
| mkdir -p "${STAGING}/include/obs" | |
| mkdir -p "${STAGING}/bindings" | |
| # 1) Framework | |
| FW_DIR="$(find "${BUILD_DIR}" -type d -name "libobs.framework" -print -quit || true)" | |
| if [ -z "${FW_DIR}" ]; then | |
| echo "ERROR: libobs.framework not found under ${BUILD_DIR}" >&2 | |
| find "${BUILD_DIR}" -maxdepth 8 -name "*.framework" -print || true | |
| exit 1 | |
| fi | |
| # Copy as obs.framework to match build.rs prebuilt link name (framework=obs) | |
| rm -rf "${STAGING}/framework/obs.framework" | |
| cp -R "${FW_DIR}" "${STAGING}/framework/obs.framework" | |
| echo "Copied framework: ${FW_DIR} -> ${STAGING}/framework/obs.framework" | |
| # Ensure the binary name matches what build.rs links: framework=obs | |
| if [ -f "${STAGING}/framework/obs.framework/libobs" ] && [ ! -e "${STAGING}/framework/obs.framework/obs" ]; then | |
| ln -sf "libobs" "${STAGING}/framework/obs.framework/obs" | |
| fi | |
| # 2) Headers | |
| if [ -d "${INSTALL_PREFIX}/include/obs" ]; then | |
| cp -R "${INSTALL_PREFIX}/include/obs/." "${STAGING}/include/obs/" | |
| echo "Copied installed headers from ${INSTALL_PREFIX}/include/obs" | |
| fi | |
| cp "${OBS_SRC}/libobs/"*.h "${STAGING}/include/obs/" 2>/dev/null || true | |
| # obsconfig.h | |
| if [ -f "${BUILD_DIR}/config/obsconfig.h" ]; then | |
| cp "${BUILD_DIR}/config/obsconfig.h" "${STAGING}/include/obs/" | |
| echo "Copied obsconfig.h" | |
| else | |
| echo "WARNING: obsconfig.h not found at ${BUILD_DIR}/config/obsconfig.h" >&2 | |
| fi | |
| # 3) Bindings (pre-generated) | |
| BINDINGS="$(find target -path "*/out/libobs_bindings.rs" -print -quit || true)" | |
| if [ -z "${BINDINGS}" ]; then | |
| echo "ERROR: libobs_bindings.rs not found in target/**/out/" >&2 | |
| find target -maxdepth 6 -name "libobs_bindings.rs" -print || true | |
| exit 1 | |
| fi | |
| cp "${BINDINGS}" "${STAGING}/bindings/libobs_bindings.rs" | |
| echo "Copied bindings from ${BINDINGS}" | |
| # 4) Metadata | |
| echo "REVO_OBS_REF=${REVO_OBS_REF}" >> "${STAGING}/build-info.env" | |
| echo "OBS_GIT=$(git -C ${OBS_SRC} describe --tags --always 2>/dev/null || echo unknown)" >> "${STAGING}/build-info.env" | |
| echo "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "${STAGING}/build-info.env" | |
| echo "ARCH=${ARCH}" >> "${STAGING}/build-info.env" | |
| echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}" >> "${STAGING}/build-info.env" | |
| echo "Artifact layout:" | |
| find "${STAGING}" -not -name '*.h' | sort | |
| echo "STAGING=${STAGING}" >> "$GITHUB_ENV" | |
| - name: Patch framework install names (make artifact portable) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| FW_DIR="${{ env.STAGING }}/framework/obs.framework" | |
| # If obs doesn't exist for some reason, create it now | |
| if [ -f "${FW_DIR}/libobs" ] && [ ! -e "${FW_DIR}/obs" ]; then | |
| ln -sf "libobs" "${FW_DIR}/obs" | |
| fi | |
| # Patch BOTH names if present, so whichever the linker uses is consistent. | |
| for FW_BIN in "${FW_DIR}/libobs" "${FW_DIR}/obs"; do | |
| if [ -f "${FW_BIN}" ]; then | |
| echo "== Patching: ${FW_BIN} ==" | |
| echo "Before:" | |
| otool -D "${FW_BIN}" || true | |
| otool -L "${FW_BIN}" || true | |
| install_name_tool -id "@rpath/obs.framework/libobs" "${FW_BIN}" | |
| echo "After:" | |
| otool -D "${FW_BIN}" || true | |
| otool -L "${FW_BIN}" || true | |
| echo "== LC_BUILD_VERSION ==" | |
| otool -l "${FW_BIN}" | grep -A2 LC_BUILD_VERSION || true | |
| echo | |
| fi | |
| done | |
| # Re-sign after modifications | |
| codesign --force --sign - "${FW_DIR}" || true | |
| - name: CALCULATED BUNDLE SIZE (system deps referenced by obs.framework) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| STAGING="${{ env.STAGING }}" | |
| FW_DIR="${STAGING}/framework/obs.framework" | |
| if [ -f "${FW_DIR}/obs" ]; then | |
| FW_BIN="${FW_DIR}/obs" | |
| else | |
| FW_BIN="${FW_DIR}/libobs" | |
| fi | |
| echo "==============================" | |
| echo "CALCULATED BUNDLE SIZE (SYSTEM DEPS)" | |
| echo "==============================" | |
| echo "Framework dir: ${FW_DIR}" | |
| echo "Framework bin: ${FW_BIN}" | |
| echo | |
| echo "[STAGING TOTAL]" | |
| du -sh "${STAGING}" || true | |
| echo | |
| echo "[FRAMEWORK TOTAL]" | |
| du -sh "${FW_DIR}" || true | |
| echo | |
| echo "[BREW INFO]" | |
| command -v brew || true | |
| BREW_PREFIX="$(brew --prefix 2>/dev/null || true)" | |
| echo "brew --prefix: ${BREW_PREFIX}" | |
| echo "Exists /usr/local/opt? $(test -d /usr/local/opt && echo yes || echo no)" | |
| echo "Exists /opt/homebrew/opt? $(test -d /opt/homebrew/opt && echo yes || echo no)" | |
| echo | |
| echo "[DEPENDENCIES FROM otool -L]" | |
| DEPS_FILE="$(mktemp)" | |
| otool -L "${FW_BIN}" \ | |
| | tail -n +2 \ | |
| | awk '{print $1}' \ | |
| | grep -vE '^(@rpath|@loader_path|@executable_path)' \ | |
| | grep -E '^/' \ | |
| | sort -u > "${DEPS_FILE}" || true | |
| sed 's/^/ - /' "${DEPS_FILE}" || true | |
| echo | |
| echo "[CHECK IF otool PATHS EXIST ON DISK]" | |
| while IFS= read -r p; do | |
| [ -n "${p}" ] || continue | |
| if [ -e "${p}" ]; then | |
| echo "OK ${p}" | |
| else | |
| echo "MISS ${p}" | |
| fi | |
| done < "${DEPS_FILE}" | |
| echo | |
| echo "[FFMPEG SIZE (by brew prefix)]" | |
| if brew --prefix ffmpeg >/dev/null 2>&1; then | |
| FFMPEG_PREFIX="$(brew --prefix ffmpeg)" | |
| echo "ffmpeg prefix: ${FFMPEG_PREFIX}" | |
| echo "ffmpeg lib dir size: " | |
| du -sh "${FFMPEG_PREFIX}/lib" || true | |
| echo "ffmpeg dylibs:" | |
| ls -lh "${FFMPEG_PREFIX}/lib"/libav*.dylib 2>/dev/null || true | |
| echo "ffmpeg dylib total:" | |
| python3 - <<'PY' | |
| import glob, os | |
| paths = glob.glob(os.path.join(os.environ["FFMPEG_PREFIX"], "lib", "libav*.dylib")) | |
| total = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) | |
| print(f"{total/1024/1024:.2f} MB") | |
| PY | |
| else | |
| echo "ffmpeg not installed (brew --prefix ffmpeg failed)" | |
| fi | |
| echo | |
| echo "[JANSSON SIZE (by brew prefix)]" | |
| if brew --prefix jansson >/dev/null 2>&1; then | |
| JANSSON_PREFIX="$(brew --prefix jansson)" | |
| echo "jansson prefix: ${JANSSON_PREFIX}" | |
| ls -lh "${JANSSON_PREFIX}/lib"/libjansson*.dylib 2>/dev/null || true | |
| python3 - <<'PY' | |
| import glob, os | |
| paths = glob.glob(os.path.join(os.environ["JANSSON_PREFIX"], "lib", "libjansson*.dylib")) | |
| total = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) | |
| print(f"{total/1024/1024:.2f} MB") | |
| PY | |
| else | |
| echo "jansson not installed (brew --prefix jansson failed)" | |
| fi | |
| echo | |
| rm -f "${DEPS_FILE}" | |
| env: | |
| FFMPEG_PREFIX: "" | |
| JANSSON_PREFIX: "" | |
| - name: Upload libobs prebuilt artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.STAGING }} | |
| path: ${{ env.STAGING }}/ | |
| if-no-files-found: error | |
| build-windows: | |
| name: Build (Windows) | |
| runs-on: windows-2025 | |
| env: | |
| RUST_BACKTRACE: "1" | |
| REVO_OBS_REF: "32.1.0-rc1" | |
| # vcpkg: prefer Release only | |
| VCPKG_DEFAULT_TRIPLET: "x64-windows-release" | |
| VCPKG_BUILD_TYPE: "release" | |
| # Optional: encourage single-config Release for CMake projects that respect it | |
| CMAKE_BUILD_TYPE: "Release" | |
| CMAKE_GENERATOR: "Ninja" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-pc-windows-msvc | |
| - name: Setup MSVC | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Select Windows SDK (>= 10.0.20348.0) | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $kitsRoot = "C:\Program Files (x86)\Windows Kits\10\Lib" | |
| if (-not (Test-Path $kitsRoot)) { | |
| throw "Windows Kits not found at: $kitsRoot" | |
| } | |
| $all = Get-ChildItem -Directory $kitsRoot | Select-Object -ExpandProperty Name | |
| Write-Host "Installed Windows SDK entries:" | |
| $all | Sort-Object | ForEach-Object { Write-Host " - $_" } | |
| # Keep only semantic SDK version folders like 10.0.22621.0, skip 'wdf' | |
| $versions = $all | Where-Object { $_ -match '^\d+\.\d+\.\d+\.\d+$' } | |
| if (-not $versions -or $versions.Count -eq 0) { | |
| throw "No Windows SDK version folders found under: $kitsRoot" | |
| } | |
| $selected = ($versions | Sort-Object {[version]$_} | Select-Object -Last 1).Trim() | |
| Write-Host "Selected Windows SDK version: $selected" | |
| if ([version]$selected -lt [version]"10.0.20348.0") { | |
| throw "Selected SDK $selected is < 10.0.20348.0 (OBS requirement)." | |
| } | |
| # Tooling typically expects trailing backslash | |
| "WindowsSDKVersion=$selected\" | Out-File -Append -Encoding utf8 $env:GITHUB_ENV | |
| "CMAKE_SYSTEM_VERSION=$selected" | Out-File -Append -Encoding utf8 $env:GITHUB_ENV | |
| - name: Install Ninja | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| choco install -y ninja | |
| ninja --version | |
| - name: Install dependencies (vcpkg, classic mode, Release only) | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| if (-not $env:VCPKG_INSTALLATION_ROOT -or $env:VCPKG_INSTALLATION_ROOT.Trim() -eq "") { | |
| $env:VCPKG_INSTALLATION_ROOT = "C:\vcpkg" | |
| } | |
| $vcpkgRoot = $env:VCPKG_INSTALLATION_ROOT | |
| Write-Host "Using vcpkg root: $vcpkgRoot" | |
| if (-not (Test-Path $vcpkgRoot)) { | |
| throw "vcpkg root does not exist: $vcpkgRoot" | |
| } | |
| $vcpkgExe = Join-Path $vcpkgRoot "vcpkg.exe" | |
| if (-not (Test-Path $vcpkgExe)) { | |
| Write-Host "vcpkg.exe not found, bootstrapping..." | |
| Push-Location $vcpkgRoot | |
| .\bootstrap-vcpkg.bat | |
| Pop-Location | |
| } | |
| & $vcpkgExe version | |
| # Release-only triplets (avoid building debug variants) | |
| & $vcpkgExe install ` | |
| ffmpeg:x64-windows-release ` | |
| mbedtls:x64-windows-release ` | |
| speexdsp:x64-windows-release ` | |
| jansson:x64-windows-release ` | |
| uthash:x64-windows-release ` | |
| simde:x64-windows-release | |
| # Export VCPKG_ROOT for subsequent steps (build.rs reads it for toolchain) | |
| "VCPKG_ROOT=$vcpkgRoot" | Out-File -Append -Encoding utf8 $env:GITHUB_ENV | |
| Write-Host "Exported VCPKG_ROOT=$vcpkgRoot" | |
| - name: Build (revo-lib) + build.rs builds OBS | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| # VCPKG_ROOT is written to GITHUB_ENV by the install step above; | |
| # it is already available as a process env var here. | |
| Write-Host "VCPKG_ROOT=$env:VCPKG_ROOT" | |
| Write-Host "CMAKE_SYSTEM_VERSION=$env:CMAKE_SYSTEM_VERSION" | |
| if (-not $env:VCPKG_ROOT -or -not (Test-Path $env:VCPKG_ROOT)) { | |
| throw "VCPKG_ROOT ('$env:VCPKG_ROOT') is not set or does not exist." | |
| } | |
| $env:VCPKG_DEFAULT_TRIPLET = "x64-windows-release" | |
| cargo build --release | |
| - name: Package artifact (prebuilt layout) | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $arch = "x86_64" | |
| $staging = "libobs-prebuilt-windows-$arch" | |
| $obsSrc = "obs-libobs\obs-studio" | |
| $buildDir = "$obsSrc\build-headless" | |
| $installDir = "$buildDir\install" | |
| New-Item -ItemType Directory -Force -Path "$staging\lib" | Out-Null | |
| New-Item -ItemType Directory -Force -Path "$staging\bin" | Out-Null | |
| New-Item -ItemType Directory -Force -Path "$staging\include\obs" | Out-Null | |
| New-Item -ItemType Directory -Force -Path "$staging\bindings" | Out-Null | |
| # 1) Import lib (obs.lib) – searched by rustc | |
| $obsLib = Get-ChildItem -Recurse "$buildDir" -Filter "obs.lib" -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($obsLib) { | |
| Copy-Item $obsLib.FullName "$staging\lib\obs.lib" | |
| Write-Host "Copied obs.lib from $($obsLib.FullName)" | |
| } else { | |
| Write-Warning "obs.lib not found under $buildDir" | |
| } | |
| # 2) DLL (obs.dll) – needed at runtime | |
| $obsDll = Get-ChildItem -Recurse "$buildDir" -Filter "obs.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($obsDll) { | |
| Copy-Item $obsDll.FullName "$staging\bin\obs.dll" | |
| Write-Host "Copied obs.dll from $($obsDll.FullName)" | |
| } else { | |
| Write-Warning "obs.dll not found under $buildDir" | |
| } | |
| # 3) Headers | |
| if (Test-Path "$installDir\include\obs") { | |
| Copy-Item -Recurse "$installDir\include\obs\*" "$staging\include\obs\" | |
| Write-Host "Copied installed headers from $installDir\include\obs" | |
| } | |
| Get-ChildItem "$obsSrc\libobs" -Filter "*.h" | ForEach-Object { | |
| Copy-Item $_.FullName "$staging\include\obs\" -Force | |
| } | |
| # obsconfig.h | |
| $obscfg = Get-ChildItem -Recurse "$buildDir" -Filter "obsconfig.h" -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($obscfg) { | |
| Copy-Item $obscfg.FullName "$staging\include\obs\obsconfig.h" -Force | |
| Write-Host "Copied obsconfig.h from $($obscfg.FullName)" | |
| } else { | |
| Write-Warning "obsconfig.h not found" | |
| } | |
| # 4) Bindings | |
| $bindings = Get-ChildItem -Recurse "target" -Filter "libobs_bindings.rs" -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($bindings) { | |
| Copy-Item $bindings.FullName "$staging\bindings\libobs_bindings.rs" | |
| Write-Host "Copied bindings from $($bindings.FullName)" | |
| } else { | |
| Write-Error "libobs_bindings.rs not found in target\**\out\" | |
| exit 1 | |
| } | |
| # 5) Metadata | |
| "REVO_OBS_REF=$env:REVO_OBS_REF" | Out-File -Append -Encoding ascii "$staging\build-info.env" | |
| "BUILD_DATE=$(Get-Date -AsUTC -Format o)" | Out-File -Append -Encoding ascii "$staging\build-info.env" | |
| "ARCH=$arch" | Out-File -Append -Encoding ascii "$staging\build-info.env" | |
| Write-Host "Artifact layout:" | |
| Get-ChildItem -Recurse $staging | Where-Object { -not $_.Name.EndsWith(".h") } | Sort-Object FullName | ForEach-Object { Write-Host $_.FullName } | |
| "STAGING=$staging" | Out-File -Append -Encoding utf8 $env:GITHUB_ENV | |
| - name: Upload Windows artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.STAGING }} | |
| path: ${{ env.STAGING }}\ | |
| if-no-files-found: error |