mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-10 07:50:19 +00:00
Added functions to copy DLL and header aliases for Enchant2 and other libraries, ensuring they are present in the specified directories.
832 lines
36 KiB
YAML
832 lines
36 KiB
YAML
name: Windows Build
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
pull_request:
|
|
branches:
|
|
- master
|
|
|
|
jobs:
|
|
windows_build:
|
|
runs-on: windows-2019
|
|
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
attestations: write
|
|
artifact-metadata: write
|
|
|
|
strategy:
|
|
matrix:
|
|
platform: [x64, win32]
|
|
arch: [x64, x86]
|
|
exclude:
|
|
- platform: x64
|
|
arch: x86
|
|
- platform: win32
|
|
arch: x64
|
|
fail-fast: false
|
|
|
|
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"
|
|
architecture: ${{ matrix.arch }}
|
|
|
|
- name: Install Dependencies (GTK3 toolchain + packagers)
|
|
env:
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
New-Item -Name "deps" -ItemType "Directory" -Force | Out-Null
|
|
|
|
# Inno Setup + IDP (kept as-is)
|
|
Invoke-WebRequest http://files.jrsoftware.org/is/5/innosetup-5.5.9-unicode.exe -OutFile deps\innosetup-unicode.exe
|
|
& deps\innosetup-unicode.exe /VERYSILENT | Out-Null
|
|
|
|
Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/idpsetup-1.5.1.exe -OutFile deps\idpsetup.exe
|
|
& deps\idpsetup.exe /VERYSILENT
|
|
|
|
# WinSparkle / gendef / perl (kept as-is)
|
|
Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/gendef-20111031.7z -OutFile deps\gendef.7z
|
|
& 7z.exe x deps\gendef.7z -oC:\gtk-build | Out-Null
|
|
|
|
Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/WinSparkle-20151011.7z -OutFile deps\WinSparkle.7z
|
|
& 7z.exe x deps\WinSparkle.7z -oC:\gtk-build\WinSparkle | Out-Null
|
|
|
|
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
|
|
|
|
# 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
|
|
|
|
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 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 Copy-AliasLib([string]$libDir, [string]$targetName, [string[]]$sourcePatterns) {
|
|
$target = Join-Path $libDir $targetName
|
|
if (Test-Path $target) { return }
|
|
|
|
$src = $null
|
|
foreach ($pat in $sourcePatterns) {
|
|
$src = Get-ChildItem -Path $libDir -File -Filter "*.lib" | Where-Object { $_.Name -match $pat } | Select-Object -First 1
|
|
if ($src) { break }
|
|
}
|
|
|
|
if ($src) {
|
|
Copy-Item $src.FullName $target -Force
|
|
Write-Host "Alias: $targetName <= $($src.Name)"
|
|
} else {
|
|
Write-Host "Alias not created: $targetName (no match in $libDir)"
|
|
}
|
|
}
|
|
|
|
function Copy-AliasDll([string]$binDir, [string]$targetName, [string[]]$sourcePatterns) {
|
|
$target = Join-Path $binDir $targetName
|
|
if (Test-Path $target) { return }
|
|
|
|
$src = $null
|
|
foreach ($pat in $sourcePatterns) {
|
|
$src = Get-ChildItem -Path $binDir -File -Filter "*.dll" | Where-Object { $_.Name -match $pat } | Select-Object -First 1
|
|
if ($src) { break }
|
|
}
|
|
|
|
if ($src) {
|
|
Copy-Item $src.FullName $target -Force
|
|
Write-Host "DLL Alias: $targetName <= $($src.Name)"
|
|
} else {
|
|
Write-Host "DLL alias not created: $targetName (no match in $binDir)"
|
|
}
|
|
}
|
|
|
|
function Ensure-HeaderAlias([string]$incRoot, [string]$targetName, [string[]]$relativeCandidates) {
|
|
$target = Join-Path $incRoot $targetName
|
|
if (Test-Path $target) { return }
|
|
|
|
foreach ($rel in $relativeCandidates) {
|
|
$src = Join-Path $incRoot $rel
|
|
if (Test-Path $src) {
|
|
Copy-Item $src $target -Force
|
|
Write-Host "Header Alias: $targetName <= $rel"
|
|
return
|
|
}
|
|
}
|
|
|
|
Write-Host "Header alias not created: $targetName (no candidate found under $incRoot)"
|
|
}
|
|
|
|
function Ensure-GlibGenmarshalWrapper([string]$gtkBin) {
|
|
$wrapperPath = Join-Path $gtkBin "glib-genmarshal"
|
|
$exePath = Join-Path $gtkBin "glib-genmarshal.exe"
|
|
|
|
# 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 }
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
# If no exe and no real tool, search for any glib-genmarshal* in bin and use that.
|
|
if (-not (Test-Path $exePath) -and -not (Test-Path $realPath)) {
|
|
$cand = Get-ChildItem -Path $gtkBin -File -Filter "glib-genmarshal*" | Select-Object -First 1
|
|
if ($cand) {
|
|
Move-Item $cand.FullName $realPath -Force
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path $exePath) -and -not (Test-Path $realPath)) {
|
|
throw "GTK3 prefix present, but no glib-genmarshal tool found under $gtkBin"
|
|
}
|
|
|
|
# Write a python wrapper that dispatches to:
|
|
# - glib-genmarshal.exe if present
|
|
# - otherwise glib-genmarshal.real (perl or python script)
|
|
$wrapper = @(
|
|
"import os, subprocess, sys",
|
|
"base = os.path.dirname(__file__)",
|
|
"exe = os.path.join(base, 'glib-genmarshal.exe')",
|
|
"real = os.path.join(base, 'glib-genmarshal.real')",
|
|
"tool = exe if os.path.exists(exe) else real",
|
|
"if not os.path.exists(tool):",
|
|
" sys.stderr.write('glib-genmarshal tool not found\\n')",
|
|
" sys.exit(1)",
|
|
"if tool.lower().endswith('.exe'):",
|
|
" sys.exit(subprocess.call([tool] + sys.argv[1:]))",
|
|
"first = b''",
|
|
"try:",
|
|
" with open(tool, 'rb') as f: first = f.readline().lower()",
|
|
"except Exception:",
|
|
" pass",
|
|
"if b'perl' in first:",
|
|
" sys.exit(subprocess.call(['perl', tool] + sys.argv[1:]))",
|
|
"sys.exit(subprocess.call([sys.executable, tool] + sys.argv[1:]))"
|
|
)
|
|
$wrapper | Set-Content -Path $wrapperPath -Encoding ASCII
|
|
}
|
|
|
|
function Ensure-LuaJit([string]$gtkInc, [string]$gtkLib, [string]$gtkBin, [string]$platform) {
|
|
# Provide <lua.h> et al + lua51.lib/dll for the lua plugin build.
|
|
$needHeaders = -not (Test-Path (Join-Path $gtkInc "lua.h"))
|
|
$needLib = -not (Test-Path (Join-Path $gtkLib "lua51.lib"))
|
|
|
|
if (-not $needHeaders -and -not $needLib) {
|
|
return
|
|
}
|
|
|
|
$zip = "deps\luajit-v2.1.zip"
|
|
$dst = "deps\luajit-src"
|
|
if (Test-Path $dst) { Remove-Item $dst -Recurse -Force }
|
|
New-Item -Path $dst -ItemType Directory -Force | Out-Null
|
|
|
|
Invoke-WebRequest https://github.com/LuaJIT/LuaJIT/archive/refs/heads/v2.1.zip -OutFile $zip
|
|
Expand-Archive -Force $zip -DestinationPath $dst
|
|
|
|
$topDir = Get-ChildItem -Path $dst -Directory | Select-Object -First 1
|
|
if (-not $topDir) { throw "LuaJIT source zip extracted, but no top directory found." }
|
|
|
|
$srcDir = Join-Path $topDir.FullName "src"
|
|
foreach ($h in @("lua.h", "lualib.h", "lauxlib.h", "luaconf.h")) {
|
|
$p = Join-Path $srcDir $h
|
|
if (-not (Test-Path $p)) { throw "LuaJIT header missing: $p" }
|
|
}
|
|
|
|
# Copy headers into the common include layouts used by various projects.
|
|
$incTargets = @(
|
|
$gtkInc,
|
|
(Join-Path $gtkInc "luajit-2.1"),
|
|
(Join-Path $gtkInc "lua5.1"),
|
|
(Join-Path $gtkInc "lua")
|
|
)
|
|
|
|
foreach ($t in $incTargets) {
|
|
if (-not (Test-Path $t)) { New-Item -Path $t -ItemType Directory -Force | Out-Null }
|
|
foreach ($h in @("lua.h", "lualib.h", "lauxlib.h", "luaconf.h")) {
|
|
Copy-Item (Join-Path $srcDir $h) (Join-Path $t $h) -Force
|
|
}
|
|
}
|
|
|
|
# Build lua51.lib/dll with MSVC if not present.
|
|
if (-not (Test-Path (Join-Path $gtkLib "lua51.lib"))) {
|
|
$vsDevCmd = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat"
|
|
if (-not (Test-Path $vsDevCmd)) { throw "VsDevCmd.bat not found at $vsDevCmd" }
|
|
|
|
$arch = if ($platform -eq "x64") { "amd64" } else { "x86" }
|
|
|
|
$cmd = @(
|
|
"""$vsDevCmd"" -no_logo -arch=$arch -host_arch=$arch",
|
|
"cd /d ""$srcDir""",
|
|
"call msvcbuild.bat"
|
|
) -join " && "
|
|
|
|
cmd /c $cmd | Out-Host
|
|
|
|
$dll = Join-Path $srcDir "lua51.dll"
|
|
$lib = Join-Path $srcDir "lua51.lib"
|
|
if (-not (Test-Path $dll) -or -not (Test-Path $lib)) {
|
|
throw "LuaJIT build finished, but lua51.dll/lib not found under $srcDir"
|
|
}
|
|
|
|
Copy-Item $dll (Join-Path $gtkBin "lua51.dll") -Force
|
|
Copy-Item $lib (Join-Path $gtkLib "lua51.lib") -Force
|
|
}
|
|
|
|
# Provide common import-lib aliases some projects expect.
|
|
Copy-AliasLib $gtkLib "lua.lib" @('^lua51\.lib$')
|
|
Copy-AliasLib $gtkLib "luajit.lib" @('^lua51\.lib$')
|
|
|
|
# Sanity check: ensure a bare <lua.h> include will work somewhere.
|
|
if (-not (Test-Path (Join-Path $gtkInc "lua.h"))) {
|
|
throw "lua.h still missing under $gtkInc after installation"
|
|
}
|
|
}
|
|
|
|
function Ensure-Zlib([string]$gtkInc, [string]$gtkLib, [string]$platform) {
|
|
# Projects explicitly link "zlib.lib". Provide it.
|
|
$want = Join-Path $gtkLib "zlib.lib"
|
|
if (Test-Path $want) { return }
|
|
|
|
# Try common alternative names first (bundles vary).
|
|
Copy-AliasLib $gtkLib "zlib.lib" @(
|
|
'^zlib1\.lib$',
|
|
'^zdll\.lib$',
|
|
'^zlibstatic\.lib$',
|
|
'^zlibwapi\.lib$',
|
|
'^zlib.*\.lib$'
|
|
)
|
|
if (Test-Path $want) { return }
|
|
|
|
# If still missing, build zlib with MSVC (fast) and drop zlib.lib into GTK lib.
|
|
$zip = "deps\zlib-1.3.1.zip"
|
|
$dst = "deps\zlib-src"
|
|
if (Test-Path $dst) { Remove-Item $dst -Recurse -Force }
|
|
New-Item -Path $dst -ItemType Directory -Force | Out-Null
|
|
|
|
Invoke-WebRequest https://github.com/madler/zlib/archive/refs/tags/v1.3.1.zip -OutFile $zip
|
|
Expand-Archive -Force $zip -DestinationPath $dst
|
|
|
|
$topDir = Get-ChildItem -Path $dst -Directory | Select-Object -First 1
|
|
if (-not $topDir) { throw "zlib source zip extracted, but no top directory found." }
|
|
|
|
$srcDir = $topDir.FullName
|
|
|
|
$vsDevCmd = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat"
|
|
if (-not (Test-Path $vsDevCmd)) { throw "VsDevCmd.bat not found at $vsDevCmd" }
|
|
|
|
$arch = if ($platform -eq "x64") { "amd64" } else { "x86" }
|
|
|
|
$cmd = @(
|
|
"""$vsDevCmd"" -no_logo -arch=$arch -host_arch=$arch",
|
|
"cd /d ""$srcDir""",
|
|
"nmake -f win32\\Makefile.msc clean",
|
|
"nmake -f win32\\Makefile.msc"
|
|
) -join " && "
|
|
|
|
cmd /c $cmd | Out-Host
|
|
|
|
$builtLib = Join-Path $srcDir "zlib.lib"
|
|
if (-not (Test-Path $builtLib)) {
|
|
# Some environments produce import lib name; try to alias those too.
|
|
Copy-AliasLib (Join-Path $srcDir ".") "zlib.lib" @('^zdll\.lib$','^zlib.*\.lib$')
|
|
if (-not (Test-Path $builtLib)) {
|
|
throw "zlib build finished, but zlib.lib was not produced under $srcDir"
|
|
}
|
|
}
|
|
|
|
Copy-Item $builtLib $want -Force
|
|
Write-Host "Installed zlib.lib => $want"
|
|
|
|
# Ensure headers exist where the solution expects them (usually already in GTK).
|
|
foreach ($h in @("zlib.h", "zconf.h")) {
|
|
$dstH = Join-Path $gtkInc $h
|
|
if (-not (Test-Path $dstH)) {
|
|
$srcH = Join-Path $srcDir $h
|
|
if (Test-Path $srcH) {
|
|
Copy-Item $srcH $dstH -Force
|
|
Write-Host "Installed header $h => $dstH"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function Ensure-LibXml2([string]$gtkLib, [string]$gtkBin, [string]$platform) {
|
|
# Projects explicitly link "libxml2.lib". Provide it.
|
|
$want = Join-Path $gtkLib "libxml2.lib"
|
|
if (Test-Path $want) { return }
|
|
|
|
# First: alias from common names shipped by different bundles.
|
|
Copy-AliasLib $gtkLib "libxml2.lib" @(
|
|
'^libxml2-2\.0\.lib$',
|
|
'^libxml2-2\.lib$',
|
|
'^libxml2_a\.lib$',
|
|
'^libxml2-static\.lib$',
|
|
'^xml2\.lib$',
|
|
'^libxml2.*\.lib$'
|
|
)
|
|
if (Test-Path $want) { return }
|
|
|
|
# Second: if only a DLL exists, generate an import library from it (gendef + lib.exe).
|
|
$dll = Get-ChildItem -Path $gtkBin -File -Filter "libxml2*.dll" | Sort-Object -Property Name | Select-Object -First 1
|
|
if (-not $dll) {
|
|
$dll = Get-ChildItem -Path $gtkBin -File -Filter "xml2*.dll" | Sort-Object -Property Name | Select-Object -First 1
|
|
}
|
|
if (-not $dll) {
|
|
throw "libxml2.lib missing and no libxml2 DLL found under $gtkBin"
|
|
}
|
|
|
|
$gendefExe = Get-ChildItem -Path "C:\gtk-build" -Recurse -File -Filter "gendef.exe" | Select-Object -First 1
|
|
if (-not $gendefExe) {
|
|
throw "gendef.exe not found under C:\gtk-build (gendef extraction failed?)"
|
|
}
|
|
|
|
$defPath = Join-Path $env:TEMP "libxml2.def"
|
|
$tmpLib = Join-Path $env:TEMP "libxml2.lib"
|
|
|
|
& $gendefExe.FullName $dll.FullName | Out-File -FilePath $defPath -Encoding ascii
|
|
|
|
if (-not (Test-Path $defPath) -or (Get-Item $defPath).Length -lt 64) {
|
|
throw "gendef produced an invalid/empty DEF for $($dll.Name)"
|
|
}
|
|
|
|
$vsDevCmd = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat"
|
|
if (-not (Test-Path $vsDevCmd)) { throw "VsDevCmd.bat not found at $vsDevCmd" }
|
|
|
|
$vcArch = if ($platform -eq "x64") { "amd64" } else { "x86" }
|
|
$machineOpt = if ($platform -eq "x64") { "X64" } else { "X86" }
|
|
|
|
$cmd = @(
|
|
"""$vsDevCmd"" -no_logo -arch=$vcArch -host_arch=$vcArch",
|
|
"lib /nologo /def:""$defPath"" /machine:$machineOpt /out:""$tmpLib"""
|
|
) -join " && "
|
|
|
|
cmd /c $cmd | Out-Host
|
|
|
|
if (-not (Test-Path $tmpLib)) {
|
|
throw "Failed to generate libxml2.lib from $($dll.Name)"
|
|
}
|
|
|
|
Copy-Item $tmpLib $want -Force
|
|
Write-Host "Generated libxml2.lib from $($dll.Name) => $want"
|
|
}
|
|
|
|
function Ensure-LibJpeg([string]$gtkLib, [string]$gtkBin, [string]$platform) {
|
|
# Projects explicitly link "libjpeg.lib". Provide it.
|
|
$want = Join-Path $gtkLib "libjpeg.lib"
|
|
if (Test-Path $want) { return }
|
|
|
|
# First: alias from common names shipped by different bundles.
|
|
# Prefer the libjpeg ABI libs; avoid turbojpeg.lib unless you really mean that API.
|
|
Copy-AliasLib $gtkLib "libjpeg.lib" @(
|
|
'^jpeg\.lib$',
|
|
'^libjpeg-8\.lib$',
|
|
'^libjpeg-9\.lib$',
|
|
'^libjpeg-7\.lib$',
|
|
'^libjpeg-6\.lib$',
|
|
'^libjpeg_a\.lib$',
|
|
'^libjpeg-static\.lib$',
|
|
'^libjpeg.*\.lib$'
|
|
)
|
|
if (Test-Path $want) { return }
|
|
|
|
# Second: if only a DLL exists, generate an import library from it (gendef + lib.exe).
|
|
$dll = Get-ChildItem -Path $gtkBin -File -Filter "libjpeg*.dll" | Sort-Object -Property Name | Select-Object -First 1
|
|
if (-not $dll) {
|
|
$dll = Get-ChildItem -Path $gtkBin -File -Filter "jpeg*.dll" | Sort-Object -Property Name | Select-Object -First 1
|
|
}
|
|
if (-not $dll) {
|
|
throw "libjpeg.lib missing and no JPEG DLL found under $gtkBin"
|
|
}
|
|
|
|
$gendefExe = Get-ChildItem -Path "C:\gtk-build" -Recurse -File -Filter "gendef.exe" | Select-Object -First 1
|
|
if (-not $gendefExe) {
|
|
throw "gendef.exe not found under C:\gtk-build (gendef extraction failed?)"
|
|
}
|
|
|
|
$defPath = Join-Path $env:TEMP "libjpeg.def"
|
|
$tmpLib = Join-Path $env:TEMP "libjpeg.lib"
|
|
|
|
& $gendefExe.FullName $dll.FullName | Out-File -FilePath $defPath -Encoding ascii
|
|
|
|
if (-not (Test-Path $defPath) -or (Get-Item $defPath).Length -lt 64) {
|
|
throw "gendef produced an invalid/empty DEF for $($dll.Name)"
|
|
}
|
|
|
|
$vsDevCmd = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat"
|
|
if (-not (Test-Path $vsDevCmd)) { throw "VsDevCmd.bat not found at $vsDevCmd" }
|
|
|
|
$vcArch = if ($platform -eq "x64") { "amd64" } else { "x86" }
|
|
$machineOpt = if ($platform -eq "x64") { "X64" } else { "X86" }
|
|
|
|
$cmd = @(
|
|
"""$vsDevCmd"" -no_logo -arch=$vcArch -host_arch=$vcArch",
|
|
"lib /nologo /def:""$defPath"" /machine:$machineOpt /out:""$tmpLib"""
|
|
) -join " && "
|
|
|
|
cmd /c $cmd | Out-Host
|
|
|
|
if (-not (Test-Path $tmpLib)) {
|
|
throw "Failed to generate libjpeg.lib from $($dll.Name)"
|
|
}
|
|
|
|
Copy-Item $tmpLib $want -Force
|
|
Write-Host "Generated libjpeg.lib from $($dll.Name) => $want"
|
|
}
|
|
|
|
function Ensure-Enchant2([string]$gtkPrefix, [string]$wantArch) {
|
|
$inc = Join-Path $gtkPrefix "include"
|
|
$bin = Join-Path $gtkPrefix "bin"
|
|
$lib = Join-Path $gtkPrefix "lib"
|
|
|
|
$hasHeader = (Test-Path (Join-Path $inc "enchant-2\enchant-provider.h")) -or (Test-Path (Join-Path $inc "enchant-provider.h"))
|
|
$hasDll = (Get-ChildItem -Path $bin -File -Filter "libenchant*.dll" -ErrorAction SilentlyContinue | Select-Object -First 1) -ne $null
|
|
$hasLib = (Get-ChildItem -Path $lib -File -Filter "libenchant*.lib" -ErrorAction SilentlyContinue | Select-Object -First 1) -ne $null
|
|
|
|
if ($hasHeader -and $hasDll -and $hasLib) { return }
|
|
|
|
Write-Host "Enchant2 not fully present in GTK prefix; attempting to build via gvsbuild and merge..."
|
|
|
|
$gvsDir = "C:\gtk-build\github\gvsbuild"
|
|
if (-not (Test-Path $gvsDir)) {
|
|
New-Item -Path "C:\gtk-build\github" -ItemType Directory -Force | Out-Null
|
|
git clone --depth 1 https://github.com/wingtk/gvsbuild.git $gvsDir
|
|
}
|
|
|
|
Push-Location $gvsDir
|
|
python -m pip install --upgrade pip
|
|
python -m pip install -r requirements.txt
|
|
|
|
$built = $false
|
|
foreach ($mod in @("enchant", "enchant2")) {
|
|
try {
|
|
Write-Host "Trying gvsbuild module: $mod"
|
|
python .\build.py build -p=$wantArch --vs-ver=16 --msys-dir=C:\tools\msys64 -c=release $mod
|
|
$built = $true
|
|
break
|
|
} catch {
|
|
Write-Host "Module $mod failed: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
Pop-Location
|
|
|
|
if (-not $built) {
|
|
throw "Could not build Enchant via gvsbuild (tried: enchant, enchant2)."
|
|
}
|
|
|
|
$srcPrefix = "C:\gtk-build\gtk\$wantArch\release"
|
|
if (-not (Test-Path $srcPrefix)) { throw "Expected gvsbuild prefix not found: $srcPrefix" }
|
|
|
|
# Merge headers
|
|
if (Test-Path (Join-Path $srcPrefix "include\enchant-2")) {
|
|
New-Item -Path (Join-Path $inc "enchant-2") -ItemType Directory -Force | Out-Null
|
|
Copy-Item (Join-Path $srcPrefix "include\enchant-2\*") (Join-Path $inc "enchant-2") -Recurse -Force
|
|
}
|
|
|
|
# Merge libs/dlls
|
|
Copy-Item (Join-Path $srcPrefix "bin\libenchant*.dll") $bin -Force -ErrorAction SilentlyContinue
|
|
Copy-Item (Join-Path $srcPrefix "lib\libenchant*.lib") $lib -Force -ErrorAction SilentlyContinue
|
|
|
|
# Re-evaluate
|
|
$hasHeader = (Test-Path (Join-Path $inc "enchant-2\enchant-provider.h")) -or (Test-Path (Join-Path $inc "enchant-provider.h"))
|
|
$hasDll = (Get-ChildItem -Path $bin -File -Filter "libenchant*.dll" -ErrorAction SilentlyContinue | Select-Object -First 1) -ne $null
|
|
$hasLib = (Get-ChildItem -Path $lib -File -Filter "libenchant*.lib" -ErrorAction SilentlyContinue | Select-Object -First 1) -ne $null
|
|
|
|
if (-not ($hasHeader -and $hasDll -and $hasLib)) {
|
|
throw "Enchant2 still missing after gvsbuild merge. Header/DLL/LIB present? $hasHeader / $hasDll / $hasLib"
|
|
}
|
|
|
|
Write-Host "Enchant2 merged into GTK prefix."
|
|
}
|
|
|
|
# ------------------------------------------
|
|
# GTK: Prefer prebuilt wingtk/gvsbuild GTK3 bundles.
|
|
# If missing for x86 (win32), build GTK3 via gvsbuild from source.
|
|
# ------------------------------------------
|
|
$wantArch = if ("${{ matrix.platform }}" -eq "x64") { "x64" } else { "x86" } # gvsbuild uses x64/x86
|
|
$wantPlat = "${{ matrix.platform }}" # solution uses x64/win32
|
|
|
|
$extractRoot = "C:\_gtk_extract"
|
|
if (Test-Path $extractRoot) { Remove-Item $extractRoot -Recurse -Force }
|
|
New-Item -Path $extractRoot -ItemType Directory -Force | Out-Null
|
|
|
|
$gtkPrefix = $null
|
|
|
|
$headers = @{
|
|
"User-Agent" = "zoitechat-ci"
|
|
"Authorization" = "Bearer $env:GITHUB_TOKEN"
|
|
"X-GitHub-Api-Version" = "2022-11-28"
|
|
}
|
|
|
|
try {
|
|
$release = Invoke-RestMethod -Headers $headers -Uri "https://api.github.com/repos/wingtk/gvsbuild/releases/latest"
|
|
|
|
# Try a couple of patterns in case naming shifts slightly.
|
|
$asset = $release.assets |
|
|
Where-Object {
|
|
($_.name -match '^GTK3_Gvsbuild_.*_(x64|x86)\.zip$' -or $_.name -match '(?i)gtk3.*(x64|x86)\.zip$') -and
|
|
$_.name -match "_$wantArch\.zip$"
|
|
} |
|
|
Select-Object -First 1
|
|
|
|
if ($asset) {
|
|
$bundlePath = "deps\gtk3-$wantArch-bundle.zip"
|
|
Invoke-WebRequest $asset.browser_download_url -OutFile $bundlePath
|
|
Expand-Archive -Force $bundlePath -DestinationPath $extractRoot
|
|
|
|
$gtkPrefix = Find-GtkPrefix $extractRoot
|
|
if (-not $gtkPrefix) { throw "GTK3 bundle extracted, but gtk.h not found. Layout unexpected." }
|
|
|
|
Write-Host "Detected GTK prefix: $gtkPrefix"
|
|
} else {
|
|
Write-Host "No prebuilt GTK3 bundle found for $wantArch. Will build GTK3 from source via gvsbuild."
|
|
}
|
|
} catch {
|
|
Write-Host "Prebuilt GTK3 discovery failed: $($_.Exception.Message)"
|
|
Write-Host "Will build GTK3 from source via gvsbuild."
|
|
}
|
|
|
|
if (-not $gtkPrefix) {
|
|
# Build GTK3 via gvsbuild (VS2019) as a fallback.
|
|
$gvsDir = "C:\gtk-build\github\gvsbuild"
|
|
if (-not (Test-Path $gvsDir)) {
|
|
New-Item -Path "C:\gtk-build\github" -ItemType Directory -Force | Out-Null
|
|
git clone --depth 1 https://github.com/wingtk/gvsbuild.git $gvsDir
|
|
}
|
|
|
|
Push-Location $gvsDir
|
|
python -m pip install --upgrade pip
|
|
python -m pip install -r requirements.txt
|
|
|
|
# Build GTK3 (3.24) for VS2019 (16), using MSYS2.
|
|
python .\build.py build -p=$wantArch --vs-ver=16 --msys-dir=C:\tools\msys64 --gtk3-ver=3.24 -c=release gtk3
|
|
Pop-Location
|
|
|
|
$gtkPrefix = "C:\gtk-build\gtk\$wantArch\release"
|
|
if (-not (Test-Path (Join-Path $gtkPrefix "include\gtk-3.0\gtk\gtk.h"))) {
|
|
throw "gvsbuild finished, but expected GTK headers were not found under $gtkPrefix"
|
|
}
|
|
}
|
|
|
|
# Normalize GTK location to the path your solution expects:
|
|
# C:\gtk-build\gtk\<platform>\release\...
|
|
$normBase = "C:\gtk-build\gtk\$wantPlat"
|
|
New-Item -Path $normBase -ItemType Directory -Force | Out-Null
|
|
$normRel = Join-Path $normBase "release"
|
|
Ensure-Junction $normRel $gtkPrefix
|
|
|
|
$gtkBin = Join-Path $normRel "bin"
|
|
$gtkLib = Join-Path $normRel "lib"
|
|
$gtkInc = Join-Path $normRel "include"
|
|
|
|
if (-not (Test-Path $gtkBin)) { throw "GTK bin dir missing at $gtkBin" }
|
|
if (-not (Test-Path $gtkLib)) { throw "GTK lib dir missing at $gtkLib" }
|
|
if (-not (Test-Path $gtkInc)) { throw "GTK include dir missing at $gtkInc" }
|
|
|
|
# glib-genmarshal: vcxproj calls python.exe <path>\glib-genmarshal (no extension).
|
|
# Ensure we always have a python wrapper named glib-genmarshal in GTK\bin.
|
|
Ensure-GlibGenmarshalWrapper $gtkBin
|
|
|
|
# Provide LuaJIT headers + import lib for the lua plugin.
|
|
Ensure-LuaJit $gtkInc $gtkLib $gtkBin $wantPlat
|
|
|
|
# Ensure zlib.lib exists (some bundles name it differently or omit it).
|
|
Ensure-Zlib $gtkInc $gtkLib $wantPlat
|
|
|
|
# Ensure libxml2.lib exists (some bundles ship only DLL or different .lib name).
|
|
Ensure-LibXml2 $gtkLib $gtkBin $wantPlat
|
|
|
|
# Ensure libjpeg.lib exists (some bundles ship jpeg.lib / libjpeg-8.lib or only DLL).
|
|
Ensure-LibJpeg $gtkLib $gtkBin $wantPlat
|
|
|
|
# Ensure Enchant2 (needed by libenchant_win8 project + packaging expectations).
|
|
Ensure-Enchant2 $normRel $wantArch
|
|
|
|
# Header aliases for projects that include flat names (quotes) instead of subdir includes.
|
|
Ensure-HeaderAlias $gtkInc "enchant-provider.h" @("enchant-2\enchant-provider.h", "enchant\enchant-provider.h")
|
|
Ensure-HeaderAlias $gtkInc "hb.h" @("harfbuzz\hb.h")
|
|
Ensure-HeaderAlias $gtkInc "hb-ot.h" @("harfbuzz\hb-ot.h")
|
|
|
|
# DLL aliases to satisfy win32\copy\copy.vcxproj (it expects older names).
|
|
Copy-AliasDll $gtkBin "freetype.dll" @('^freetype\.dll$', '^libfreetype-6\.dll$', '^libfreetype.*\.dll$')
|
|
Copy-AliasDll $gtkBin "fontconfig.dll" @('^fontconfig\.dll$', '^libfontconfig-1\.dll$', '^libfontconfig.*\.dll$')
|
|
Copy-AliasDll $gtkBin "gdk-win32-2.0.dll" @('^gdk-3-0\.dll$', '^libgdk-3-0\.dll$', '^gdk-3.*\.dll$')
|
|
Copy-AliasDll $gtkBin "gtk-win32-2.0.dll" @('^gtk-3-0\.dll$', '^libgtk-3-0\.dll$', '^gtk-3.*\.dll$')
|
|
Copy-AliasDll $gtkBin "libenchant.dll" @('^libenchant-2\.dll$', '^libenchant-2-2\.dll$', '^libenchant.*\.dll$')
|
|
Copy-AliasDll $gtkBin "ffi-7.dll" @('^ffi-7\.dll$', '^libffi-7\.dll$', '^libffi-8\.dll$', '^ffi-8\.dll$', '^libffi-.*\.dll$')
|
|
Copy-AliasDll $gtkBin "libxml2.dll" @('^libxml2\.dll$', '^libxml2-2\.dll$', '^libxml2-2-2\.dll$', '^xml2\.dll$', '^libxml2.*\.dll$')
|
|
Copy-AliasDll $gtkBin "cairo.dll" @('^cairo\.dll$', '^libcairo-2\.dll$', '^libcairo.*\.dll$')
|
|
|
|
# Compatibility aliases for differing .lib names across bundles.
|
|
Copy-AliasLib $gtkLib "gtk-3.0.lib" @(
|
|
'^gtk-3-0\.lib$',
|
|
'^gtk-3\.lib$',
|
|
'^gtk-3.*\.lib$',
|
|
'^gtk-win32-2\.0\.lib$'
|
|
)
|
|
|
|
Copy-AliasLib $gtkLib "gtk-win32-2.0.lib" @(
|
|
'^gtk-3\.0\.lib$',
|
|
'^gtk-3-0\.lib$',
|
|
'^gtk-3\.lib$',
|
|
'^gtk-3.*\.lib$'
|
|
)
|
|
|
|
# gdk: project expects gdk-3.0.lib but bundles often ship gdk-3.lib / gdk-3-0.lib
|
|
Copy-AliasLib $gtkLib "gdk-3.0.lib" @(
|
|
'^gdk-3-0\.lib$',
|
|
'^gdk-3\.lib$',
|
|
'^gdk-3.*\.lib$',
|
|
'^gdk-win32-2\.0\.lib$'
|
|
)
|
|
|
|
Copy-AliasLib $gtkLib "gdk-win32-2.0.lib" @(
|
|
'^gdk-3\.0\.lib$',
|
|
'^gdk-3-0\.lib$',
|
|
'^gdk-3\.lib$',
|
|
'^gdk-3.*\.lib$'
|
|
)
|
|
|
|
# OpenSSL legacy names (keep older projects happy if they still reference these)
|
|
Copy-AliasLib $gtkLib "ssleay32.lib" @('^libssl\.lib$', '^ssl\.lib$')
|
|
Copy-AliasLib $gtkLib "libeay32.lib" @('^libcrypto\.lib$', '^crypto\.lib$')
|
|
|
|
# Persist GTK root for later steps.
|
|
"GTK_ROOT=$normRel" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
# Resolve python root from setup-python
|
|
$pyRoot = $env:pythonLocation
|
|
if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" }
|
|
|
|
# Create BOTH paths because the .vcxproj hard-codes python-3.14\...
|
|
foreach ($pyDir in @("C:\gtk-build\python-3.14.2", "C:\gtk-build\python-3.14")) {
|
|
New-Item -Path $pyDir -ItemType Directory -Force | Out-Null
|
|
$target = Join-Path $pyDir "${{ matrix.platform }}"
|
|
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
|
|
New-Item -Path $pyDir -Name "${{ matrix.platform }}" -ItemType Junction -Value $pyRoot | Out-Null
|
|
}
|
|
|
|
python -m pip install --upgrade pip
|
|
python -m pip install cffi
|
|
|
|
- name: Build
|
|
shell: cmd
|
|
run: |
|
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat"
|
|
|
|
set "GTKROOT=%GTK_ROOT%"
|
|
if not exist "%GTKROOT%\include\gtk-3.0\gtk\gtk.h" (
|
|
echo Missing GTK headers under %GTKROOT%
|
|
dir "%GTKROOT%\include\gtk-3.0\gtk"
|
|
exit /b 1
|
|
)
|
|
|
|
if not exist "%GTKROOT%\lib\zlib.lib" (
|
|
echo Missing zlib.lib under %GTKROOT%\lib
|
|
dir "%GTKROOT%\lib"
|
|
exit /b 1
|
|
)
|
|
|
|
if not exist "%GTKROOT%\lib\libxml2.lib" (
|
|
echo Missing libxml2.lib under %GTKROOT%\lib
|
|
dir "%GTKROOT%\lib"
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
|
|
if not exist "%GTKROOT%\lib\libjpeg.lib" (
|
|
echo Missing libjpeg.lib under %GTKROOT%\lib
|
|
dir "%GTKROOT%\lib"
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
|
|
rem Make MSVC find hb.h and enchant-provider.h (they live in subdirs under include\)
|
|
set "INCLUDE=%GTKROOT%\include\harfbuzz;%GTKROOT%\include\enchant-2;%GTKROOT%\include\freetype2;%INCLUDE%"
|
|
|
|
rem Sanity: these are expected by win32\copy\copy.vcxproj
|
|
if not exist "%GTKROOT%\bin\freetype.dll" (
|
|
echo Missing freetype.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\fontconfig.dll" (
|
|
echo Missing fontconfig.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\gdk-win32-2.0.dll" (
|
|
echo Missing gdk-win32-2.0.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\gtk-win32-2.0.dll" (
|
|
echo Missing gtk-win32-2.0.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\libenchant.dll" (
|
|
echo Missing libenchant.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\ffi-7.dll" (
|
|
echo Missing ffi-7.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\libxml2.dll" (
|
|
echo Missing libxml2.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
if not exist "%GTKROOT%\bin\cairo.dll" (
|
|
echo Missing cairo.dll under %GTKROOT%\bin
|
|
dir "%GTKROOT%\bin"
|
|
exit /b 1
|
|
)
|
|
|
|
set "PATH=%PERL_BIN%;%GTKROOT%\bin;%PATH%"
|
|
set "LIB=%GTKROOT%\lib;%LIB%"
|
|
set "INCLUDE=%GTKROOT%\include;%INCLUDE%"
|
|
|
|
set "PYTHON_DIR=C:\gtk-build\python-3.14.2\${{ matrix.platform }}"
|
|
if not exist "%PYTHON_DIR%\libs\python314.lib" (
|
|
echo Missing %PYTHON_DIR%\libs\python314.lib
|
|
dir "%PYTHON_DIR%\libs"
|
|
exit /b 1
|
|
)
|
|
|
|
set "LIB=%PYTHON_DIR%\libs;%LIB%"
|
|
set "INCLUDE=%PYTHON_DIR%\include;%INCLUDE%"
|
|
|
|
msbuild win32\zoitechat.sln /m /verbosity:minimal /p:Configuration=Release /p:Platform=${{ matrix.platform }}
|
|
|
|
- name: Preparing Artifacts
|
|
shell: cmd
|
|
run: |
|
|
move ..\zoitechat-build\${{ matrix.platform }}\ZoiteChat*.exe .\
|
|
move ..\zoitechat-build .\
|
|
|
|
- name: Upload Installer
|
|
id: upload_installer
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: Installer ${{ matrix.arch }}
|
|
path: ZoiteChat*.exe
|
|
|
|
- name: Attest Installer (Artifact Attestation)
|
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
|
uses: actions/attest-build-provenance@v3
|
|
with:
|
|
subject-name: Installer ${{ matrix.arch }}
|
|
subject-digest: sha256:${{ steps.upload_installer.outputs.artifact-digest }}
|
|
|
|
- name: Upload Build Files
|
|
id: upload_buildfiles
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: Build Files ${{ matrix.arch }}
|
|
path: zoitechat-build
|
|
|
|
- name: Attest Build Files (Artifact Attestation)
|
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
|
uses: actions/attest-build-provenance@v3
|
|
with:
|
|
subject-name: Build Files ${{ matrix.arch }}
|
|
subject-digest: sha256:${{ steps.upload_buildfiles.outputs.artifact-digest }}
|