diff --git a/.github/actions/libmpv-windows/action.yml b/.github/actions/libmpv-windows/action.yml deleted file mode 100644 index c8d21c1..0000000 --- a/.github/actions/libmpv-windows/action.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: libmpv (Windows) -description: > - Provide libmpv's Windows development files. `libmpv2-sys` emits - `cargo:rustc-link-lib=mpv`, and mpv's Windows *player* build ships neither - mpv.lib nor libmpv-2.dll — they come from the separate mpv-dev archive. Sets - LIB for the linker, PATH so binaries find the DLL at run time, and - MPV_DEV_DIR for `scripts/build.ps1`. - -outputs: - dir: - description: Directory holding libmpv-2.dll and mpv.lib. - value: ${{ steps.mpv.outputs.dir }} - -runs: - using: composite - steps: - # lib.exe, for turning mpv.def into an import library. - - uses: ilammy/msvc-dev-cmd@v1 - - - id: mpv - shell: pwsh - run: | - $ErrorActionPreference = 'Stop' - $feed = [xml](Invoke-WebRequest -UseBasicParsing ` - 'https://sourceforge.net/projects/mpv-player-windows/rss?path=/libmpv').Content - # The "v3" variants are x86-64-v3 builds; take the baseline one. - $item = $feed.rss.channel.item | - Where-Object { $_.link -match 'mpv-dev-x86_64-2[^/]*\.7z/download$' } | - Select-Object -First 1 - if (-not $item) { throw 'no mpv-dev build in the SourceForge feed' } - - $archive = Join-Path $env:RUNNER_TEMP 'mpv-dev.7z' - $dir = Join-Path $env:RUNNER_TEMP 'mpv-dev' - Invoke-WebRequest -UseBasicParsing $item.link -OutFile $archive - 7z x $archive "-o$dir" -y | Out-Null - - $dll = Get-ChildItem -Path $dir -Filter 'libmpv-2.dll' -Recurse | - Select-Object -First 1 - if (-not $dll) { throw "libmpv-2.dll not found under $dir" } - $libDir = $dll.Directory.FullName - - # /NAME matters: without it the import library references mpv.dll, and - # the file that actually ships is libmpv-2.dll. - lib.exe /def:"$libDir\mpv.def" /name:libmpv-2.dll ` - /out:"$libDir\mpv.lib" /machine:x64 | Out-Null - if ($LASTEXITCODE -ne 0) { throw 'lib.exe failed to build mpv.lib' } - - "dir=$libDir" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8 - "MPV_DEV_DIR=$libDir" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 - "LIB=$libDir;$env:LIB" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 - $libDir | Out-File $env:GITHUB_PATH -Append -Encoding utf8 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0e9b1f..d64bbed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,11 +10,8 @@ env: jobs: gate: - strategy: - fail-fast: false - matrix: - os: [ubuntu-24.04, windows-latest] - runs-on: ${{ matrix.os }} + name: Gate (Linux) + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -26,22 +23,49 @@ jobs: - uses: Swatinem/rust-cache@v2 - # libmpv for pstr-player. On Windows the DLL and import library are - # bundled from the mpv-dev build rather than installed system-wide. - - name: Install libmpv (Linux) - if: runner.os == 'Linux' + # libmpv for pstr-player. + - name: Install libmpv run: | sudo apt-get update sudo apt-get install -y libmpv-dev - # Without this the test binaries do not link: there is no mpv.lib on the - # runner. See .github/actions/libmpv-windows. - - name: Install libmpv (Windows) - if: runner.os == 'Windows' - uses: ./.github/actions/libmpv-windows - - run: cargo fmt --all -- --check - run: cargo clippy --workspace --all-targets -- -D warnings - run: cargo test --workspace --locked + + # The Windows artifacts are cross-compiled from Linux with mingw-w64 — see + # scripts/build-windows.sh — so this checks the target that actually ships. + # It is a compile check, not a test run: nothing here executes a Windows + # binary. libmpv is not linked at build time by anything but `-l mpv`, which + # is why the import library out of the mpv-dev archive is all it needs. + windows-cross: + name: Gate (Windows cross) + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.96" + components: clippy + targets: x86_64-pc-windows-gnu + + - uses: Swatinem/rust-cache@v2 + + - name: Install the cross toolchain + run: | + sudo apt-get update + sudo apt-get install -y mingw-w64 p7zip-full + + - name: Fetch libmpv's Windows development files + env: + GITHUB_TOKEN: ${{ github.token }} + run: scripts/build-windows.sh --fetch-mpv mpv + + - name: clippy (x86_64-pc-windows-gnu) + run: | + RUSTFLAGS="-L native=$PWD/dist/mpv-dev" \ + cargo clippy --workspace --all-targets \ + --target x86_64-pc-windows-gnu -- -D warnings diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3cf1fe1..db68f99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,28 +96,35 @@ jobs: dist/*.rpm if-no-files-found: error + # Cross-compiled from Linux with mingw-w64, and the .msi built by wixl rather + # than WiX — scripts/build-windows.sh, which is how these artifacts have been + # produced by hand. A windows runner would need MSVC's mpv.lib, and current + # mpv-dev archives ship only the mingw import library. windows: name: Windows artifacts needs: verify - runs-on: windows-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: "1.96" + targets: x86_64-pc-windows-gnu - uses: Swatinem/rust-cache@v2 - # Sets MPV_DEV_DIR, which is what build.ps1 reads when -MpvDev is absent. - - name: Install libmpv - uses: ./.github/actions/libmpv-windows + # mingw-w64 for the cross compile, msitools for wixl, p7zip for the + # mpv-dev archive. + - name: Install the cross toolchain + run: | + sudo apt-get update + sudo apt-get install -y mingw-w64 msitools zip p7zip-full - # build.ps1 installs the WiX toolset itself if `wix` is missing, and the - # runner has the .NET SDK it needs for that. - name: Build the portable .zip and the .msi - shell: pwsh - run: scripts\build.ps1 -Artifacts zip,msi + env: + GITHUB_TOKEN: ${{ github.token }} + run: scripts/build-windows.sh --fetch-mpv - uses: actions/upload-artifact@v4 with: diff --git a/packaging/README.md b/packaging/README.md index 40482bf..7cd2f7a 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -69,18 +69,20 @@ so the linker wants an import library named `mpv.lib` and the process wants `libmpv-2.dll` at run time. Neither ships with mpv's Windows *player* build — both come from the separate **mpv-dev** archive: - + -Unpack it and point the script at it: +(The SourceForge project these are better known by mirrors the same builds, but +its `/download` URLs hand anything that does not look like a browser an HTML +interstitial, so `--fetch-mpv` goes to the source.) -```powershell -scripts\build.ps1 -MpvDev C:\mpv-dev -``` - -If that directory has `mpv.def` but no `mpv.lib`, the script generates the import -library with `lib.exe` (`/name:libmpv-2.dll`, so it references the DLL that -actually ships). It finds `lib.exe` on `PATH` or imports the MSVC environment via -`vswhere`, so a plain PowerShell session works. +**The cross build from Linux is the supported path, and the one CI uses** — +`scripts/build-windows.sh --fetch-mpv` fetches the archive, links against its +`libmpv.dll.a` with mingw-w64 and builds the `.msi` with `wixl`. On a real +Windows box `scripts\build.ps1 -MpvDev C:\mpv-dev` does the MSVC equivalent, but +note that it needs an `mpv.lib` or an `mpv.def` to generate one from with +`lib.exe`, and **current mpv-dev archives ship neither** — only the mingw import +library. Producing `mpv.lib` from a recent archive means writing the `.def` +yourself from `dumpbin /exports libmpv-2.dll`. There is no static libmpv worth shipping, so **"standalone exe" means the exe plus `libmpv-2.dll` beside it** — that pair, plus `pstr.exe` and the README, is @@ -131,9 +133,9 @@ almost every field in it is computed. ## Releasing A release is a `v` tag on `main`; `.github/workflows/release.yml` does -the rest. It runs the CI gate and `scripts/build.sh tarball deb rpm` on Linux, -`scripts\build.ps1 -Artifacts zip,msi` on Windows, and publishes both sets plus -a `SHA256SUMS` to a GitHub release. So the steps are: +the rest. Every job runs on Linux: `scripts/build.sh tarball deb rpm` for the +Linux artifacts and `scripts/build-windows.sh --fetch-mpv` for the Windows ones, +published together with a `SHA256SUMS` to a GitHub release. So the steps are: ```bash # 1. bump Cargo.toml's workspace version *and* packaging/PKGBUILD's pkgver diff --git a/scripts/build-windows.sh b/scripts/build-windows.sh index a1c6b64..a683e1e 100755 --- a/scripts/build-windows.sh +++ b/scripts/build-windows.sh @@ -45,7 +45,13 @@ readonly CLI_BIN="pstr.exe" # The mpv-dev archive: libmpv-2.dll plus the import library to link against. # mpv's *player* build ships neither. -readonly MPV_INDEX="https://sourceforge.net/projects/mpv-player-windows/rss?path=/libmpv" +# +# Fetched from shinchiro's releases rather than the SourceForge mirror the +# archive is better known by: SourceForge's `/download` URLs answer anything +# that does not look like a browser with an HTML interstitial, which lands as a +# file called mpv-dev.7z that is not an archive. These are the same builds — the +# SourceForge project mirrors them. +readonly MPV_RELEASE="https://api.github.com/repos/shinchiro/mpv-winbuild-cmake/releases/latest" VERSION="$(grep -m1 '^version' "$ROOT/Cargo.toml" | cut -d'"' -f2)" readonly VERSION @@ -66,6 +72,7 @@ usage() { usage: scripts/build-windows.sh [options] [artifact ...] artifacts + mpv resolve libmpv's development files into dist/mpv-dev and stop binaries cargo build --release --target ${TARGET}, then stage dist/windows zip dist/${PKGNAME}-${VERSION}-x86_64-windows.zip msi dist/${PKGNAME}-${VERSION}-x64.msi (needs wixl) @@ -100,7 +107,7 @@ done [[ ${#TARGETS[@]} -eq 0 ]] && TARGETS=(all) for t in "${TARGETS[@]}"; do case "$t" in - binaries|zip|msi|all) ;; + mpv|binaries|zip|msi|all) ;; *) echo "unknown artifact: $t" >&2; usage >&2; exit 2 ;; esac done @@ -128,15 +135,20 @@ fetch_mpv() { have curl || die "--fetch-mpv needs curl" have 7z || die "--fetch-mpv needs 7z (p7zip)" + # The asset names are mpv-dev---git-.7z; the date is what + # keeps this off the i686, aarch64 and v3 builds in the same release. local url - url="$(curl -sL --max-time 60 "$MPV_INDEX" \ - | grep -o '[^<]*mpv-dev-x86_64-2[^<]*\.7z/download' \ - | sed 's|||; s|||' | head -1)" - [[ -n "$url" ]] || die "could not find an mpv-dev build in the SourceForge feed" + url="$(curl -sL --max-time 60 ${GITHUB_TOKEN:+-H "Authorization: Bearer $GITHUB_TOKEN"} "$MPV_RELEASE" \ + | grep -o '"browser_download_url": *"[^"]*mpv-dev-x86_64-20[0-9]*-git-[^"]*\.7z"' \ + | sed 's|.*: *"||; s|"$||' | head -1)" + [[ -n "$url" ]] || die "no mpv-dev build in the latest shinchiro/mpv-winbuild-cmake release" - log "downloading $(basename "$(dirname "$url")")" + log "downloading $(basename "$url")" mkdir -p "$dest" curl -L --max-time 600 -o "$dest.7z" "$url" + # A download that fetched an error page instead of the archive fails inside 7z + # with something unrelated to what went wrong; say it here. + [[ "$(head -c2 "$dest.7z")" == "7z" ]] || die "$url did not return a 7z archive" 7z x -y -o"$dest" "$dest.7z" >/dev/null rm -f "$dest.7z" MPV_DEV="$dest" @@ -156,9 +168,9 @@ resolve_mpv() { fi [[ -n "$MPV_DEV" ]] || die "$(cat < or set MPV_DEV_DIR. EOF )" @@ -278,10 +290,13 @@ make_msi() { mkdir -p "$DIST" # Only the compile and the staging copy need libmpv; repackaging out of # dist/windows does not, so `--skip-build msi` works with no mpv-dev at hand. -[[ " ${TARGETS[*]} " == *" binaries "* ]] && resolve_mpv +if [[ " ${TARGETS[*]} " == *" binaries "* || " ${TARGETS[*]} " == *" mpv "* ]]; then + resolve_mpv +fi for t in "${TARGETS[@]}"; do case "$t" in + mpv) log "libmpv at $MPV_DIR" ;; # resolve_mpv above did the work binaries) build; stage ;; zip) [[ -d "$OUTDIR" ]] || die 'nothing staged — run the binaries artifact first'; make_zip ;; msi) [[ -d "$OUTDIR" ]] || die 'nothing staged — run the binaries artifact first'; make_msi ;;