mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
init
This commit is contained in:
commit
a1b345a029
80 files changed
+28033
No files matched your search
@@ -0,0 +1,265 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Release build + packaging for Windows: a portable .exe and an .msi installer.
|
||||
|
||||
.DESCRIPTION
|
||||
The Unix side is scripts/build.sh; this is the half that needs MSVC and WiX.
|
||||
|
||||
libmpv is the one thing that makes a Windows build of this repo different from
|
||||
`cargo build`. libmpv2-sys emits `cargo:rustc-link-lib=mpv`, so the linker
|
||||
wants an import library called mpv.lib, and the process wants libmpv-2.dll at
|
||||
run time. Neither ships with mpv's Windows *player* build — they come from the
|
||||
separate "mpv-dev" archive:
|
||||
|
||||
https://sourceforge.net/projects/mpv-player-windows/files/libmpv/
|
||||
|
||||
Unpack it somewhere and point this script at it with -MpvDev or $env:MPV_DEV_DIR.
|
||||
If it contains mpv.def but no mpv.lib, the import library is generated here
|
||||
with lib.exe.
|
||||
|
||||
There is no static libmpv worth shipping, so "standalone .exe" means the exe
|
||||
plus libmpv-2.dll next to it — which is what the portable .zip contains.
|
||||
|
||||
.EXAMPLE
|
||||
scripts\build.ps1 -MpvDev C:\mpv-dev
|
||||
scripts\build.ps1 -Artifacts msi -SkipBuild
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
# Directory holding libmpv-2.dll plus mpv.lib or mpv.def.
|
||||
[string] $MpvDev = $env:MPV_DEV_DIR,
|
||||
|
||||
# exe | zip | msi | all
|
||||
[ValidateSet('exe', 'zip', 'msi', 'all')]
|
||||
[string[]] $Artifacts = @('all'),
|
||||
|
||||
# Reuse target\release from a previous run.
|
||||
[switch] $SkipBuild,
|
||||
|
||||
# Rust target triple; the default is the host.
|
||||
[string] $Target = 'x86_64-pc-windows-msvc',
|
||||
|
||||
# Authenticode signing, if you have a certificate. Both or neither.
|
||||
[string] $SignCertThumbprint,
|
||||
[string] $TimestampUrl = 'http://timestamp.digicert.com'
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$Root = Split-Path -Parent $PSScriptRoot
|
||||
$Dist = Join-Path $Root 'dist'
|
||||
$OutDir = Join-Path $Dist 'windows'
|
||||
$Pkg = Join-Path $Root 'packaging\windows'
|
||||
|
||||
$Version = (Select-String -Path (Join-Path $Root 'Cargo.toml') -Pattern '^version\s*=\s*"([^"]+)"' `
|
||||
| Select-Object -First 1).Matches[0].Groups[1].Value
|
||||
|
||||
function Log ($m) { Write-Host "==> $m" -ForegroundColor Magenta }
|
||||
function Warn ($m) { Write-Host "warning: $m" -ForegroundColor Yellow }
|
||||
function Die ($m) { Write-Host "error: $m" -ForegroundColor Red; exit 1 }
|
||||
|
||||
if ($Artifacts -contains 'all') { $Artifacts = @('exe', 'zip', 'msi') }
|
||||
|
||||
# ------------------------------------------------------------------ libmpv ---
|
||||
|
||||
function Resolve-MpvDev {
|
||||
if (-not $MpvDev) {
|
||||
Die @"
|
||||
no libmpv development files. Download the mpv-dev archive from
|
||||
https://sourceforge.net/projects/mpv-player-windows/files/libmpv/
|
||||
unpack it, and pass -MpvDev <dir> or set MPV_DEV_DIR.
|
||||
"@
|
||||
}
|
||||
if (-not (Test-Path $MpvDev)) { Die "-MpvDev path does not exist: $MpvDev" }
|
||||
|
||||
$dll = Get-ChildItem -Path $MpvDev -Filter 'libmpv-2.dll' -Recurse -ErrorAction SilentlyContinue |
|
||||
Select-Object -First 1
|
||||
if (-not $dll) { Die "libmpv-2.dll not found under $MpvDev" }
|
||||
$dir = $dll.DirectoryName
|
||||
|
||||
$lib = Join-Path $dir 'mpv.lib'
|
||||
if (-not (Test-Path $lib)) {
|
||||
$def = Join-Path $dir 'mpv.def'
|
||||
if (-not (Test-Path $def)) {
|
||||
Die "neither mpv.lib nor mpv.def in $dir — the archive is not an mpv-dev build"
|
||||
}
|
||||
Log 'generating mpv.lib from mpv.def'
|
||||
Ensure-MsvcTools
|
||||
# /NAME matters: without it the import library would reference mpv.dll,
|
||||
# and the file that actually ships is libmpv-2.dll.
|
||||
& lib.exe /def:"$def" /name:libmpv-2.dll /out:"$lib" /machine:x64 | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { Die 'lib.exe failed to build mpv.lib' }
|
||||
}
|
||||
|
||||
[pscustomobject]@{ Dir = $dir; Dll = $dll.FullName; Lib = $lib }
|
||||
}
|
||||
|
||||
# lib.exe and link.exe come from a Developer prompt. If this is a plain
|
||||
# PowerShell session, find the toolchain with vswhere and import its environment.
|
||||
function Ensure-MsvcTools {
|
||||
if (Get-Command lib.exe -ErrorAction SilentlyContinue) { return }
|
||||
|
||||
$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
|
||||
if (-not (Test-Path $vswhere)) { Die 'lib.exe not on PATH and vswhere.exe not found — run from a Developer PowerShell' }
|
||||
|
||||
$vsPath = & $vswhere -latest -products * `
|
||||
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
||||
if (-not $vsPath) { Die 'no Visual Studio C++ toolchain found' }
|
||||
|
||||
$devCmd = Join-Path $vsPath 'Common7\Tools\VsDevCmd.bat'
|
||||
Log 'importing the MSVC environment'
|
||||
cmd /c "`"$devCmd`" -arch=amd64 -host_arch=amd64 >nul && set" | ForEach-Object {
|
||||
if ($_ -match '^([^=]+)=(.*)$') { Set-Item -Path "env:$($Matches[1])" -Value $Matches[2] }
|
||||
}
|
||||
if (-not (Get-Command lib.exe -ErrorAction SilentlyContinue)) { Die 'still no lib.exe after importing VsDevCmd' }
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------- build ---
|
||||
|
||||
function Invoke-Build ($mpv) {
|
||||
if ($SkipBuild) { Log 'skipping cargo build'; return }
|
||||
|
||||
# The dev-only path patch; say so plainly rather than deep in a resolve error.
|
||||
$manifest = Get-Content (Join-Path $Root 'Cargo.toml') -Raw
|
||||
if ($manifest -match '(?m)^\[patch\.crates-io\]' -and -not (Test-Path (Join-Path $Root '..\proton-sdk-rs'))) {
|
||||
Die 'Cargo.toml still carries [patch.crates-io] -> ../proton-sdk-rs, but that checkout is missing.'
|
||||
}
|
||||
|
||||
# MSVC reads the library search path out of LIB.
|
||||
$env:LIB = "$($mpv.Dir);$env:LIB"
|
||||
|
||||
Log "cargo build --release --target $Target"
|
||||
Push-Location $Root
|
||||
try {
|
||||
& cargo build --release --locked --target $Target --bin proton-stream --bin pstr
|
||||
if ($LASTEXITCODE -ne 0) { Die 'cargo build failed' }
|
||||
} finally { Pop-Location }
|
||||
}
|
||||
|
||||
function Stage ($mpv) {
|
||||
Log 'staging into dist\windows'
|
||||
$rel = Join-Path $Root "target\$Target\release"
|
||||
foreach ($f in 'proton-stream.exe', 'pstr.exe') {
|
||||
if (-not (Test-Path (Join-Path $rel $f))) { Die "$f missing from $rel — drop -SkipBuild" }
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
|
||||
Copy-Item (Join-Path $rel 'proton-stream.exe') $OutDir -Force
|
||||
Copy-Item (Join-Path $rel 'pstr.exe') $OutDir -Force
|
||||
Copy-Item $mpv.Dll $OutDir -Force
|
||||
Copy-Item (Join-Path $Root 'README.md') $OutDir -Force
|
||||
|
||||
if ($SignCertThumbprint) {
|
||||
foreach ($f in 'proton-stream.exe', 'pstr.exe') {
|
||||
Invoke-Sign (Join-Path $OutDir $f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Sign ($path) {
|
||||
Log "signing $(Split-Path -Leaf $path)"
|
||||
$cert = Get-ChildItem Cert:\CurrentUser\My, Cert:\LocalMachine\My |
|
||||
Where-Object Thumbprint -eq $SignCertThumbprint | Select-Object -First 1
|
||||
if (-not $cert) { Die "no certificate with thumbprint $SignCertThumbprint" }
|
||||
Set-AuthenticodeSignature -FilePath $path -Certificate $cert `
|
||||
-TimestampServer $TimestampUrl -HashAlgorithm SHA256 | Out-Null
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------- portable ---
|
||||
|
||||
function New-Zip {
|
||||
$out = Join-Path $Dist "proton-stream-$Version-x86_64-windows.zip"
|
||||
Log "zip -> $(Split-Path -Leaf $out)"
|
||||
if (Test-Path $out) { Remove-Item $out }
|
||||
Compress-Archive -Path (Join-Path $OutDir '*') -DestinationPath $out
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------- msi ---
|
||||
|
||||
function Ensure-Wix {
|
||||
if (Get-Command wix -ErrorAction SilentlyContinue) { return }
|
||||
if (-not (Get-Command dotnet -ErrorAction SilentlyContinue)) {
|
||||
Die 'the .msi needs the WiX toolset: install the .NET SDK, then `dotnet tool install --global wix`'
|
||||
}
|
||||
Log 'installing the WiX toolset'
|
||||
& dotnet tool install --global wix | Out-Null
|
||||
$env:PATH = "$env:USERPROFILE\.dotnet\tools;$env:PATH"
|
||||
if (-not (Get-Command wix -ErrorAction SilentlyContinue)) { Die 'wix still not on PATH after install' }
|
||||
}
|
||||
|
||||
function New-Msi ($mpv) {
|
||||
Ensure-Wix
|
||||
# WixUI_InstallDir lives in the UI extension, which is per-installation state
|
||||
# rather than per-project; adding it twice is a no-op.
|
||||
& wix extension add -g WixToolset.UI.wixext 2>&1 | Out-Null
|
||||
|
||||
# The RTF the license dialog shows. Prefer the repository's own LICENSE, so
|
||||
# the installer cannot drift from it; fall back to the checked-in copy.
|
||||
$rtf = Join-Path $Pkg 'license.rtf'
|
||||
$repoLicense = Join-Path $Root 'LICENSE'
|
||||
if (Test-Path $repoLicense) {
|
||||
$rtf = Join-Path $Dist 'license.rtf'
|
||||
# RTF escapes are backslash, brace-open and brace-close; paragraphs are
|
||||
# \par. Done per line, because a lookbehind over already-rewritten line
|
||||
# endings is a good way to emit \par twice.
|
||||
$body = ((Get-Content $repoLicense) | ForEach-Object {
|
||||
($_ -replace '\\', '\\') -replace '([{}])', '\$1'
|
||||
}) -join "\par`r`n"
|
||||
@"
|
||||
{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Segoe UI;}}
|
||||
\viewkind4\uc1\pard\f0\fs20
|
||||
$body
|
||||
}
|
||||
"@ | Set-Content -Path $rtf -Encoding ASCII
|
||||
} else {
|
||||
Warn 'no LICENSE in the repo root; the installer shows packaging\windows\license.rtf'
|
||||
}
|
||||
|
||||
$out = Join-Path $Dist "proton-stream-$Version-x64.msi"
|
||||
Log "msi -> $(Split-Path -Leaf $out)"
|
||||
|
||||
# Every -d value is built into a string first: PowerShell does not evaluate a
|
||||
# parenthesised expression glued to the middle of a bare argument token, so
|
||||
# `-d MpvDll=(Join-Path ...)` would be passed through literally.
|
||||
$wxs = Join-Path $Pkg 'proton-stream.wxs'
|
||||
$mpvDll = Join-Path $OutDir (Split-Path -Leaf $mpv.Dll)
|
||||
$icon = Join-Path $Pkg 'proton-stream.ico'
|
||||
$readme = Join-Path $Root 'README.md'
|
||||
|
||||
$wixArgs = @(
|
||||
'build', '-arch', 'x64', '-ext', 'WixToolset.UI.wixext', $wxs,
|
||||
'-d', "Version=$Version",
|
||||
'-d', "BinDir=$OutDir",
|
||||
'-d', "MpvDll=$mpvDll",
|
||||
'-d', "IconFile=$icon",
|
||||
'-d', "LicenseRtf=$rtf",
|
||||
'-d', "ReadMe=$readme",
|
||||
'-o', $out
|
||||
)
|
||||
& wix @wixArgs
|
||||
if ($LASTEXITCODE -ne 0) { Die 'wix build failed' }
|
||||
|
||||
if ($SignCertThumbprint) { Invoke-Sign $out }
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------- main ---
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $Dist | Out-Null
|
||||
$mpv = Resolve-MpvDev
|
||||
Invoke-Build $mpv
|
||||
Stage $mpv
|
||||
|
||||
foreach ($a in $Artifacts) {
|
||||
switch ($a) {
|
||||
'exe' { } # Stage already produced dist\windows\proton-stream.exe
|
||||
'zip' { New-Zip }
|
||||
'msi' { New-Msi $mpv }
|
||||
}
|
||||
}
|
||||
|
||||
Log 'done — dist\'
|
||||
Get-ChildItem $Dist -File | ForEach-Object {
|
||||
' {0,10:N0} KB {1}' -f ($_.Length / 1KB), $_.Name
|
||||
}
|
||||
Reference in new issue
Block a user