diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index c8b88b82..21e6ba0d 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -32,6 +32,18 @@ jobs: steps: - uses: actions/checkout@v4 + # MSYS2 is required for the gvsbuild-from-source fallback path. + - name: Setup MSYS2 (for GTK build fallback) + uses: msys2/setup-msys2@v2 + with: + msys2-location: C:\tools\msys64 + update: true + install: >- + base-devel + git + unzip + p7zip + - uses: actions/setup-python@v5 with: python-version: "3.14.2" @@ -63,63 +75,33 @@ jobs: Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/perl-5.20.0-${{ matrix.arch }}.7z -OutFile deps\perl-${{ matrix.arch }}.7z & 7z.exe x deps\perl-${{ matrix.arch }}.7z -oC:\gtk-build\perl-5.20\${{ matrix.platform }} | Out-Null - # ------------------------------------------ - # GTK: download wingtk/gvsbuild GTK3 bundle and normalize into: - # C:\gtk-build\gtk\\release\{bin,include,lib} - # ------------------------------------------ - $wantArch = if ("${{ matrix.platform }}" -eq "x64") { "x64" } else { "x86" } - $wantPlat = "${{ matrix.platform }}" + # Discover perl.exe and persist its bin dir. + $perlExe = Get-ChildItem -Path "C:\gtk-build\perl-5.20\${{ matrix.platform }}" -Recurse -File -Filter "perl.exe" | Select-Object -First 1 + if (-not $perlExe) { throw "perl.exe not found under C:\gtk-build\perl-5.20\${{ matrix.platform }}" } + "PERL_BIN=$($perlExe.Directory.FullName)" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 - $extractRoot = "C:\_gtk_extract" - if (Test-Path $extractRoot) { Remove-Item $extractRoot -Recurse -Force } - New-Item -Path $extractRoot -ItemType Directory -Force | Out-Null + function Find-GtkPrefix([string]$root) { + $gtkH = Get-ChildItem -Path $root -Recurse -File -Filter "gtk.h" | + Where-Object { $_.FullName -match '\\include\\gtk-3\.0\\gtk\\gtk\.h$' } | + Select-Object -First 1 + if (-not $gtkH) { return $null } + return $gtkH.Directory.Parent.Parent.Parent.FullName # ...\include\gtk-3.0\gtk\gtk.h -> prefix + } - function Get-PEMachine([string]$path) { - try { - $fs = [System.IO.File]::Open($path, 'Open', 'Read', 'ReadWrite') - try { - $br = New-Object System.IO.BinaryReader($fs) - $mz = $br.ReadUInt16() - if ($mz -ne 0x5A4D) { return $null } # MZ - $fs.Seek(0x3C, [System.IO.SeekOrigin]::Begin) | Out-Null - $peOff = $br.ReadUInt32() - $fs.Seek($peOff, [System.IO.SeekOrigin]::Begin) | Out-Null - $peSig = $br.ReadUInt32() - if ($peSig -ne 0x00004550) { return $null } # PE\0\0 - $machine = $br.ReadUInt16() - return $machine - } finally { - $fs.Close() - } - } catch { - return $null + function Ensure-Junction([string]$linkPath, [string]$targetPath) { + if (Test-Path $linkPath) { + cmd /c rmdir /s /q "$linkPath" | Out-Null } + New-Item -Path $linkPath -ItemType Junction -Value $targetPath | Out-Null } - function Ensure-Dir([string]$p) { - if (-not (Test-Path $p)) { New-Item -Path $p -ItemType Directory -Force | Out-Null } - } - - function Pick-GtkPrefix([string]$root) { - $libs = Get-ChildItem -Path $root -Recurse -File -Filter "*.lib" -ErrorAction SilentlyContinue - $preferred = @('^gtk-3\.0\.lib$', '^gtk-3-0\.lib$', '^gtk-3\.lib$') - foreach ($rx in $preferred) { - $cand = $libs | Where-Object { $_.Name -match $rx } | Select-Object -First 1 - if ($cand) { return (Split-Path -Parent $cand.Directory.FullName) } - } - $cand2 = $libs | Where-Object { $_.Name -match '^gtk-3.*\.lib$' } | Select-Object -First 1 - if ($cand2) { return (Split-Path -Parent $cand2.Directory.FullName) } - return $null - } - - function Copy-AliasLib([string]$gtkLibDir, [string]$targetName, [string[]]$sourceNameRegexes) { - $target = Join-Path $gtkLibDir $targetName + function Copy-AliasLib([string]$libDir, [string]$targetName, [string[]]$sourcePatterns) { + $target = Join-Path $libDir $targetName if (Test-Path $target) { return } - $allLibs = Get-ChildItem -Path $gtkLibDir -File -Filter "*.lib" -ErrorAction SilentlyContinue $src = $null - foreach ($rx in $sourceNameRegexes) { - $src = $allLibs | Where-Object { $_.Name -match $rx } | Select-Object -First 1 + foreach ($pat in $sourcePatterns) { + $src = Get-ChildItem -Path $libDir -File -Filter "*.lib" | Where-Object { $_.Name -match $pat } | Select-Object -First 1 if ($src) { break } } @@ -127,97 +109,97 @@ jobs: Copy-Item $src.FullName $target -Force Write-Host "Alias: $targetName <= $($src.Name)" } else { - Write-Host "Alias not created: $targetName (no match in $gtkLibDir)" + Write-Host "Alias not created: $targetName (no match in $libDir)" } } - function Ensure-GenmarshalReady([string]$gtkBinDir, [string]$gtkPrefix, [string]$wantPlat) { - Ensure-Dir $gtkBinDir + function Ensure-GlibGenmarshalWrapper([string]$gtkBin) { + $wrapperPath = Join-Path $gtkBin "glib-genmarshal" + $exePath = Join-Path $gtkBin "glib-genmarshal.exe" - $wantMachine = if ($wantPlat -eq "x64") { 0x8664 } else { 0x014c } + # If a non-exe tool exists, move it aside so our wrapper name is stable. + $realPath = Join-Path $gtkBin "glib-genmarshal.real" + if (Test-Path $realPath) { Remove-Item $realPath -Force } - $binScript = Join-Path $gtkBinDir "glib-genmarshal" - $binExe = Join-Path $gtkBinDir "glib-genmarshal.exe" - - # 1) If we already have glib-genmarshal (no extension) in bin, prefer it. - if (Test-Path $binScript) { - $m = Get-PEMachine $binScript - if ($m) { - # It's a PE binary without .exe. Make an .exe copy for subprocess callers, and keep python wrapper. - if ($m -ne $wantMachine) { - throw "glib-genmarshal in bin is PE but wrong arch (machine=0x{0:X})." -f $m - } - Copy-Item $binScript $binExe -Force - $wrapperLines = @( - "import os, subprocess, sys", - "tool = os.path.join(os.path.dirname(__file__), 'glib-genmarshal.exe')", - "sys.exit(subprocess.call([tool] + sys.argv[1:]))" - ) - $wrapperLines | Set-Content -Path $binScript -Encoding ASCII - return + if (Test-Path $wrapperPath) { + # If it's already our wrapper, keep it. Otherwise move to .real. + $first = (Get-Content -Path $wrapperPath -TotalCount 1 -ErrorAction SilentlyContinue) + if ($first -notmatch 'import os') { + Move-Item $wrapperPath $realPath -Force } + } - # Not PE: likely a script. If it's python-ish, we're done because vcxproj calls python.exe