Revision control

Copy as Markdown

# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
# This script performs manual copying and patching of the zlib source to support
# multi-architecture builds on Windows using Microsoft's nmake and Makefile.msc.
#
# Reasons for this approach:
#
# 1. In-source build system:
# zlib's build system (Makefile.msc) writes all build artifacts directly into the source
# directory. To allow concurrent builds for different architectures (e.g., x64 and arm64),
# we copy the relevant source files into per-architecture build directories to isolate artifacts.
#
# 2. Incompatible linker base address:
# The default Makefile.msc contains a hardcoded image base address ('-base:0x5A4C0000') for the
# linker. This is invalid for ARM64 targets, which require base addresses above 4 GB. The script
# patches this line out to prevent linker errors.
#
# 3. Broken #include in zconf.h:
# zconf.h may erroneously include '<unistd.h>', which doesn't exist on Windows. While Visual Studio 2022
# builds tolerate this, we patch it out to ensure compatibility with older toolchains.
#
# These workarounds allow us to run reproducible, architecture-specific builds in CI without modifying
# the original source tree or requiring upstream changes.
[CmdletBinding(PositionalBinding = $false)]
param (
[switch] $SkipEnvVar,
[string] $InstallDir,
[switch] $Help
)
. "$PSScriptRoot\helpers.ps1"
. "$PSScriptRoot\zlib-helpers.ps1"
$HELP_MESSAGE = @"
zlib.ps1 - Builds zlib for Windows with multi-architecture support.
Usage:
zlib.ps1 [-InstallDir <path>] [-SkipEnvVar] [-Help]
Options:
-InstallDir <path> Root directory for build artifacts. A per-architecture
subfolder is created underneath it. Defaults to a
'build' folder inside the extracted zlib source.
-SkipEnvVar Build without setting the ZLIB_PATH_* environment
variables at the end. Allows the script to run without
elevated privileges.
-Help Show this help and exit.
"@
$VERSION='1.3.1'
$SHA1='f535367b1a11e2f9ac3bec723fb007fbc0d189e5'
$WIN32_DIRECTORY='win32'
$MAKEFILE="$WIN32_DIRECTORY\Makefile.msc"
function BuildZlib {
param (
[Parameter(Mandatory)]
[CpuArch] $HostArchitecture,
[Parameter(Mandatory)]
[CpuArch] $TargetArchitecture
)
PrepareBuildEnvironment -HostArchitecture $HostArchitecture -TargetArchitecture $TargetArchitecture
Invoke-NMake -NmakeArgs @('/f', "$MAKEFILE")
}
function CopySource {
param (
[Parameter(Mandatory)]
[string] $BuildRoot,
[Parameter(Mandatory)]
[CpuArch] $TargetArchitecture
)
$testDirectory='test'
$buildDirectory = GetBuildDirectory -BuildRoot $BuildRoot -TargetArchitecture $TargetArchitecture
$win32BuildDirectory = "$buildDirectory\$WIN32_DIRECTORY"
$testBuildDirectory = "$buildDirectory\$testDirectory"
New-Item -Path $buildDirectory -ItemType 'Directory'
New-Item -Path $win32BuildDirectory -ItemType 'Directory'
New-Item -Path $testBuildDirectory -ItemType 'Directory'
Copy-Item '*' -Include '*.c','*.h' -Destination $buildDirectory
Copy-Item "$WIN32_DIRECTORY\*" -Include '*.def','*.msc','*.rc' -Destination $win32BuildDirectory
Copy-Item "$testDirectory\*" -Include '*.c' -Destination $testBuildDirectory
}
function GetBuildDirectory {
param (
[Parameter(Mandatory)]
[string] $BuildRoot,
[Parameter(Mandatory)]
[CpuArch] $TargetArchitecture
)
$architectureDirectory = CpuArchToString -Architecture $TargetArchitecture
return "$BuildRoot\$architectureDirectory"
}
function GetSource {
$unzipDirectory = "C:\"
$zlibName="zlib-$VERSION"
$zlibDirectory = "$unzipDirectory$zlibName"
$downloadPath = "C:\Windows\Temp\$zlibName.tar.gz"
Write-Host "Fetching zlib $VERSION..."
Download $urlPublic $urlCached $downloadPath
Verify-Checksum $downloadPath $SHA1
Extract-tar_gz $downloadPath $unzipDirectory
Remove $downloadPath
return $zlibDirectory
}
function GetTargetArchitectures {
param (
[Parameter(Mandatory)]
[CpuArch] $HostArchitecture
)
$targetArhitectures = @([CpuArch]::arm64)
if ($HostArchitecture -eq [CpuArch]::x64) {
$targetArhitectures += [CpuArch]::x64
}
return $targetArhitectures
}
function PatchMakefile {
$pattern = '-base:\s*0x[0-9A-Fa-f]+'
(Get-Content $MAKEFILE) | ForEach-Object {
$_ -replace $pattern, ''
} | Set-Content $MAKEFILE
}
function PatchSource {
PatchZconf
PatchMakefile
}
function PatchZconf {
$zconf = 'zconf.h'
$pattern = '#\s*include\s*<unistd\.h>'
(Get-Content $zconf) | Where-Object {
$_ -notmatch $pattern
} | Set-Content $zconf
}
function PrepareBuild {
param (
[Parameter(Mandatory)]
[string] $BuildRoot,
[Parameter(Mandatory)]
[CpuArch] $TargetArchitecture
)
CopySource -BuildRoot $BuildRoot -TargetArchitecture $TargetArchitecture
}
function PrepareBuildEnvironment {
param (
[Parameter(Mandatory)]
[CpuArch] $HostArchitecture,
[Parameter(Mandatory)]
[CpuArch] $TargetArchitecture
)
$hostArhitecture = CpuArchToString -Architecture $HostArchitecture
$targetArhitecture = CpuArchToString -Architecture $TargetArchitecture
if (-not $(EnterVSDevShell -HostArch $hostArhitecture -Arch $targetArhitecture)) {
throw "Failed to prepare build environment for ${hostArhitecture}_${targetArhitecture}"
}
}
function SetZlibEnvironmentVariable {
param (
[Parameter(Mandatory)]
[string] $BuildRoot,
[Parameter(Mandatory)]
[CpuArch] $TargetArchitecture
)
$buildDirectory = GetBuildDirectory -BuildRoot $BuildRoot -TargetArchitecture $TargetArchitecture
$environmentVariableName = GetZlibEnvironmentVariableName -TargetArchitecture $TargetArchitecture
Set-EnvironmentVariable $environmentVariableName $buildDirectory
}
function ShowHelp {
Write-Host $HELP_MESSAGE
}
if ($Help) {
ShowHelp
return
}
$zlibDirectory = GetSource
$hostArchitecture = Get-CpuArchitecture
$targetArchitectures = GetTargetArchitectures -HostArchitecture $hostArchitecture
$buildRoot = if ($InstallDir) { $InstallDir } else { "$zlibDirectory\build" }
Push-Location $zlibDirectory
try {
foreach ($targetArchitecture in $targetArchitectures) {
PrepareBuild -BuildRoot $buildRoot -TargetArchitecture $targetArchitecture
$buildDirectory = GetBuildDirectory -BuildRoot $buildRoot -TargetArchitecture $targetArchitecture
Push-Location $buildDirectory
try {
PatchSource
BuildZlib -HostArchitecture $hostArchitecture -TargetArchitecture $targetArchitecture
if (-not $SkipEnvVar) {
SetZlibEnvironmentVariable -BuildRoot $buildRoot -TargetArchitecture $targetArchitecture
}
}
finally {
Pop-Location
}
}
}
finally {
Pop-Location
}