From 01368932b03840327cfb80d77cb4e512ff91e66a Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Fri, 1 May 2020 21:16:41 +0300 Subject: [PATCH] Add AppVeyor configuration for Windows release builds --- .gitignore | 1 - appveyor.yml | 95 +++++++++ release/windows/build-curl.ps1 | 41 ++++ release/windows/build-dbus.ps1 | 28 +++ release/windows/build-expat.ps1 | 26 +++ release/windows/build-openssl.ps1 | 31 +++ release/windows/build-qt.ps1 | 97 ++++++++++ release/windows/build-transmission.ps1 | 83 ++++++++ release/windows/build-zlib.ps1 | 22 +++ release/windows/main.ps1 | 255 +++++++++++++++++++++++++ release/windows/toolchain.ps1 | 17 ++ 11 files changed, 695 insertions(+), 1 deletion(-) create mode 100644 appveyor.yml create mode 100644 release/windows/build-curl.ps1 create mode 100644 release/windows/build-dbus.ps1 create mode 100644 release/windows/build-expat.ps1 create mode 100644 release/windows/build-openssl.ps1 create mode 100644 release/windows/build-qt.ps1 create mode 100644 release/windows/build-transmission.ps1 create mode 100644 release/windows/build-zlib.ps1 create mode 100644 release/windows/main.ps1 create mode 100644 release/windows/toolchain.ps1 diff --git a/.gitignore b/.gitignore index a34fd15f3..4a2533de7 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,4 @@ macosx/Info.plist macosx/Transmission.app macosx/en.lproj/*~.nib po/*.mo -/release third-party/miniupnp/miniupnpcstrings.h diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..bf00e8d4d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,95 @@ +version: '{build}' + +environment: + AWS_ACCESS_KEY_ID: + secure: JH2KJ09654cSwhYup2MKb80kK60+nezvUmFzBay7tUI= + AWS_SECRET_ACCESS_KEY: + secure: fum5aRKLhJvxh3UQhiQVt2acV4eke8GiGdMhHIW/uuQC7wztj4T9tJWp5IO1U7m4 + AWS_S3_BUCKET_NAME: + secure: Bf3x1Iruxg+l3tp+an+g9kWhBexLLw/69gEt9bEu7Zk= + + matrix: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TR_ARCH: x86 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TR_ARCH: x64 + +for: +- + matrix: + only: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + + clone_folder: '%SystemDrive%\%TR_ARCH%-project' + + install: + - pwsh: | + $Version = git describe --tags --abbrev=10 --always + if ($Version -ne $Env:APPVEYOR_REPO_BRANCH) { + $version += "-${Env:APPVEYOR_REPO_BRANCH}" + } + + $BuildIndex = 0 + appveyor UpdateBuild -Version $Version + while ($LastExitCode -ne 0) { + $BuildIndex += 1 + appveyor UpdateBuild -Version "${Version}+${BuildIndex}" + } + + git submodule update --init --recursive + + choco install ActivePerl + choco install nasm + choco install jom + choco install imagemagick.tool + choco install wixtoolset --version 3.11.2 + + Remove-Item -Path (Join-Path $Env:SystemDrive OpenSSL-Win32) -Recurse + Remove-Item -Path (Join-Path $Env:SystemDrive OpenSSL-Win64) -Recurse + + Install-Module -Name SignPath + + build_script: + - pwsh: | + $Env:PATH = @( + (Join-Path $Env:SystemDrive Perl64 bin) + (Join-Path $Env:ProgramFiles NASM) + (Join-Path ${Env:ProgramFiles(x86)} 'WiX Toolset v3.11' bin) + $Env:PATH + ) -join [System.IO.Path]::PathSeparator + + Set-ExecutionPolicy -Scope Process Bypass + + try { + & (Join-Path $Env:APPVEYOR_BUILD_FOLDER release windows main.ps1) ` + -Mode Build ` + -BuildArch $env:TR_ARCH + } catch { + Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue + exit 1 + } + + test_script: + - pwsh: | + Set-ExecutionPolicy -Scope Process Bypass + + try { + & (Join-Path $Env:APPVEYOR_BUILD_FOLDER release windows main.ps1) ` + -Mode Test ` + -BuildArch $env:TR_ARCH + } catch { + Write-Error ("{1}{0}{2}{0}{3}" -f [Environment]::NewLine, $_.ToString(), $_.InvocationInfo.PositionMessage, $_.ScriptStackTrace) -ErrorAction Continue + exit 1 + } + + artifacts: + - path: '*.msi' + - path: '*-pdb.zip' + + deploy: + - provider: Webhook + url: https://app.signpath.io/API/v1/8c96c8c9-a72c-4b46-a53c-80aad617f6bc/Integrations/AppVeyor?ProjectKey=transmission&SigningPolicyKey=test-signing + authorization: + secure: PrvcykaHmPgJ0ENht1q58tCfjRcmybiOeHYrvtQtAGsfahWvniAfP66DqHxv872acpyf3FpJn2ETCeszoVuFGA== + on: + APPVEYOR_REPO_TAG: true diff --git a/release/windows/build-curl.ps1 b/release/windows/build-curl.ps1 new file mode 100644 index 000000000..e976739b3 --- /dev/null +++ b/release/windows/build-curl.ps1 @@ -0,0 +1,41 @@ +#!/usr/bin/env pwsh + +$global:CurlVersion = '7.70.0' + +$global:CurlDeps = @( + 'OpenSsl' + 'Zlib' +) + +function global:Build-Curl([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir) { + $Filename = "curl-${CurlVersion}.tar.gz" + $Url = "https://curl.haxx.se/download/${Filename}" + + $SourceDir = Invoke-DownloadAndUnpack $Url $Filename + $BuildDir = Join-Path $SourceDir .build + + $ConfigOptions = @( + '-DCMAKE_BUILD_TYPE=RelWithDebInfo' + "-DCMAKE_INSTALL_PREFIX=${PrefixDir}" + "-DCMAKE_PREFIX_PATH=${DepsPrefixDir}" + '-DCMAKE_USE_OPENSSL=ON' + '-DCURL_WINDOWS_SSPI=OFF' + '-DBUILD_CURL_EXE=OFF' + '-DBUILD_TESTING=OFF' + '-DCURL_DISABLE_DICT=ON' + '-DCURL_DISABLE_GOPHER=ON' + '-DCURL_DISABLE_IMAP=ON' + '-DCURL_DISABLE_SMTP=ON' + '-DCURL_DISABLE_POP3=ON' + '-DCURL_DISABLE_RTSP=ON' + '-DCURL_DISABLE_TFTP=ON' + '-DCURL_DISABLE_TELNET=ON' + '-DCURL_DISABLE_LDAP=ON' + '-DCURL_DISABLE_LDAPS=ON' + '-DENABLE_MANUAL=OFF' + ) + + Invoke-CMakeBuildAndInstall $SourceDir $BuildDir $ConfigOptions + Invoke-NativeCommand cmake -E remove_directory (Join-Path $PrefixDir lib cmake CURL) # until we support it + Copy-Item -Path (Join-Path $BuildDir lib libcurl.pdb) -Destination (Join-Path $PrefixDir bin) +} diff --git a/release/windows/build-dbus.ps1 b/release/windows/build-dbus.ps1 new file mode 100644 index 000000000..a6babfa7b --- /dev/null +++ b/release/windows/build-dbus.ps1 @@ -0,0 +1,28 @@ +#!/usr/bin/env pwsh + +$global:DBusVersion = '1.12.16' + +$global:DBusDeps = @( + 'Expat' +) + +function global:Build-DBus([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir) { + $Filename = "dbus-${DBusVersion}.tar.gz" + $Url = "https://dbus.freedesktop.org/releases/dbus/${Filename}" + + $SourceDir = Invoke-DownloadAndUnpack $Url $Filename + $BuildDir = Join-Path $SourceDir .build + + $ConfigOptions = @( + '-DCMAKE_BUILD_TYPE=RelWithDebInfo' + "-DCMAKE_INSTALL_PREFIX=${PrefixDir}" + "-DCMAKE_PREFIX_PATH=${DepsPrefixDir}" + '-DDBUS_BUILD_TESTS=OFF' + ) + + # Patch to remove "-3" (or whatever) revision suffix part from DLL name since Qt doesn't seem to support that and we don't really need it + Edit-TextFile (Join-Path $SourceDir cmake modules MacrosAutotools.cmake) '^.*_LIBRARY_REVISION.*' '' + + Invoke-CMakeBuildAndInstall (Join-Path $SourceDir cmake) $BuildDir $ConfigOptions + Copy-Item -Path (Join-Path $BuildDir bin dbus-1.pdb) -Destination (Join-Path $PrefixDir bin) +} diff --git a/release/windows/build-expat.ps1 b/release/windows/build-expat.ps1 new file mode 100644 index 000000000..1c928ddf2 --- /dev/null +++ b/release/windows/build-expat.ps1 @@ -0,0 +1,26 @@ +#!/usr/bin/env pwsh + +$global:ExpatVersion = '2.2.9' + +$global:ExpatDeps = @() + +function global:Build-Expat([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir) { + $Filename = "expat-${ExpatVersion}.tar.bz2" + $Url = "https://github.com/libexpat/libexpat/releases/download/R_$($ExpatVersion.replace(".", "_"))/${Filename}" + + $SourceDir = Invoke-DownloadAndUnpack $Url $Filename + $BuildDir = Join-Path $SourceDir .build + + $ConfigOptions = @( + '-DCMAKE_BUILD_TYPE=RelWithDebInfo' + "-DCMAKE_INSTALL_PREFIX=${PrefixDir}" + "-DCMAKE_PREFIX_PATH=${DepsPrefixDir}" + '-DEXPAT_BUILD_EXAMPLES=OFF' + '-DEXPAT_BUILD_TESTS=OFF' + '-DEXPAT_BUILD_TOOLS=OFF' + '-DEXPAT_SHARED_LIBS=ON' + ) + + Invoke-CMakeBuildAndInstall $SourceDir $BuildDir $ConfigOptions + Copy-Item -Path (Join-Path $BuildDir libexpat.pdb) -Destination (Join-Path $PrefixDir bin) +} diff --git a/release/windows/build-openssl.ps1 b/release/windows/build-openssl.ps1 new file mode 100644 index 000000000..ff81d8e00 --- /dev/null +++ b/release/windows/build-openssl.ps1 @@ -0,0 +1,31 @@ +#!/usr/bin/env pwsh + +$global:OpenSslVersion = '1.1.1g' + +$global:OpenSslDeps = @() + +function global:Build-OpenSsl([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir) { + $Filename = "openssl-${OpenSslVersion}.tar.gz" + $Url = "https://www.openssl.org/source/${Filename}" + + $SourceDir = Invoke-DownloadAndUnpack $Url $Filename + $BuildDir = $SourceDir + + $ConfigName = if ($Arch -eq 'x86') { 'VC-WIN32' } else { 'VC-WIN64A' } + $ConfigOptions = @( + "--prefix=${PrefixDir}" + $ConfigName + 'shared' + 'no-comp' + 'no-dso' + 'no-engine' + 'no-hw' + 'no-stdio' + 'no-tests' + ) + + Push-Location -Path $BuildDir + Invoke-VcEnvCommand perl Configure @ConfigOptions + Invoke-VcEnvCommand jom install_dev + Pop-Location +} diff --git a/release/windows/build-qt.ps1 b/release/windows/build-qt.ps1 new file mode 100644 index 000000000..476cbf9ba --- /dev/null +++ b/release/windows/build-qt.ps1 @@ -0,0 +1,97 @@ +#!/usr/bin/env pwsh + +$global:QtVersion = '5.14.2' + +$global:QtDeps = @( + 'DBus' + 'OpenSsl' + 'Zlib' +) + +function global:Build-Qt([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir) { + $Filename = "qt-everywhere-src-${QtVersion}.zip" # tar.xz has some names truncated (e.g. .../double-conversion.h -> .../double-conv) + $Url = "http://download.qt.io/archive/qt/$($QtVersion -replace '\.\d+$', '')/${QtVersion}/single/${Filename}" + + $ArchiveBase = "qt-everywhere-src-${QtVersion}" + $UnpackFlags = @( + (Join-Path $ArchiveBase qtactiveqt '*') + (Join-Path $ArchiveBase qtbase '*') + (Join-Path $ArchiveBase qttools '*') + (Join-Path $ArchiveBase qttranslations '*') + (Join-Path $ArchiveBase qtwinextras '*') + (Join-Path $ArchiveBase .gitmodules) + (Join-Path $ArchiveBase configure.bat) + (Join-Path $ArchiveBase configure.json) + (Join-Path $ArchiveBase qt.pro) + ) + + $SourceDir = Invoke-DownloadAndUnpack $Url $Filename $UnpackFlags + $BuildDir = Join-Path $SourceDir .build + + $ConfigOptions = @( + '-platform'; 'win32-msvc' + '-mp' + # '-ltcg' # error C1002 on VS 2019 16.5.4 + '-opensource' + '-confirm-license' + '-prefix'; $PrefixDir + '-release' + '-force-debug-info' + '-dbus' + '-ssl' + '-openssl' + '-system-zlib' + '-qt-pcre' + '-qt-libpng' + '-qt-libjpeg' + '-no-opengl' + '-no-direct2d' + '-no-freetype' + '-no-harfbuzz' + '-no-sql-db2' + '-no-sql-ibase' + '-no-sql-mysql' + '-no-sql-oci' + '-no-sql-odbc' + '-no-sql-psql' + '-no-sql-sqlite' + '-no-sql-sqlite2' + '-no-sql-tds' + '-nomake'; 'examples' + '-nomake'; 'tests' + '-nomake'; 'tools' + '-I'; (Join-Path $DepsPrefixDir include) + '-L'; (Join-Path $DepsPrefixDir lib) + ) + + if ($env:LDFLAGS) { + # Patch to add our linker flags, mainly /PDBALTPATH + Edit-TextFile (Join-Path $SourceDir qtbase mkspecs win32-msvc qmake.conf) '(^QMAKE_CXXFLAGS\b.*)' "`$1`nQMAKE_LFLAGS += ${env:LDFLAGS}" + } + + # No need in GUI tools + Edit-TextFile (Join-Path $SourceDir qttools src src.pro) 'qtHaveModule[(]gui[)]' 'qtHaveModule(hughey)' + Edit-TextFile (Join-Path $SourceDir qttools src src.pro) 'qtHaveModule[(]widgets[)]' 'qtHaveModule(digits)' + Edit-TextFile (Join-Path $SourceDir qttools src linguist linguist.pro) 'qtHaveModule[(]widgets[)]' 'qtHaveModule(digits)' + + Invoke-NativeCommand cmake -E remove_directory $BuildDir + $env:PATH = @( + (Join-Path $PrefixDir bin) + (Join-Path $DepsPrefixDir bin) + (Join-Path $BuildDir qtbase lib) + $env:PATH + ) -join [System.IO.Path]::PathSeparator + + New-Item -Path $BuildDir -ItemType Directory -ErrorAction Ignore | Out-Null + Push-Location -Path $BuildDir + Invoke-VcEnvCommand (Join-Path $SourceDir configure) @ConfigOptions + Invoke-VcEnvCommand jom + Invoke-VcEnvCommand jom install + Pop-Location + + # install target doesn't copy PDBs for release DLLs + Get-Childitem -Path (Join-Path $BuildDir qtbase lib) | ` + ForEach-Object { if ($_ -is [System.IO.DirectoryInfo] -or $_.Name -like '*.pdb') { Copy-Item -Path $_.FullName -Destination (Join-Path $PrefixDir lib) -Filter '*.pdb' -Recurse -Force } } + Get-Childitem -Path (Join-Path $BuildDir qtbase plugins) | ` + ForEach-Object { if ($_ -is [System.IO.DirectoryInfo] -or $_.Name -like '*.pdb') { Copy-Item -Path $_.FullName -Destination (Join-Path $PrefixDir plugins) -Filter '*.pdb' -Recurse -Force } } +} diff --git a/release/windows/build-transmission.ps1 b/release/windows/build-transmission.ps1 new file mode 100644 index 000000000..66415d007 --- /dev/null +++ b/release/windows/build-transmission.ps1 @@ -0,0 +1,83 @@ +#!/usr/bin/env pwsh + +function global:Build-Transmission([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir, [string] $SourceDir, [string] $ArtifactsDir) { + $BuildDir = Join-Path $SourceDir .build + + $env:PATH = @( + (Join-Path $DepsPrefixDir bin) + $env:PATH + ) -join [System.IO.Path]::PathSeparator + + $ConfigOptions = @( + '-DCMAKE_BUILD_TYPE=RelWithDebInfo' + "-DCMAKE_INSTALL_PREFIX=${PrefixDir}" + "-DCMAKE_PREFIX_PATH=${DepsPrefixDir}" + "-DTR_THIRD_PARTY_DIR:PATH=${PrefixDir}" + "-DTR_QT_DIR:PATH=${PrefixDir}" + ) + + Invoke-CMakeBuildAndInstall $SourceDir $BuildDir $ConfigOptions + + $DebugSymbolsDir = Join-Path $BuildDir dbg + New-Item -Path $DebugSymbolsDir -ItemType Directory -ErrorAction Ignore | Out-Null + + foreach ($x in @('remote', 'create', 'edit', 'show', 'daemon', 'qt')) { + # Copy-Item -Path (Join-Path $PrefixDir bin "transmission-${x}.exe") -Destination (Join-Path $PrefixDir bin) + Get-ChildItem -Path $BuildDir -Filter "transmission-${x}.pdb" -Recurse | ` + Select-Object -First 1 | ` + ForEach-Object { Copy-Item -Path $_.FullName -Destination $DebugSymbolsDir } + } + + $OpenSslLibSuffix = if ($Arch -eq 'x86') { '' } else { '-x64' } + foreach ($x in @('libcurl', "libcrypto-1_1${OpenSslLibSuffix}", "libssl-1_1${OpenSslLibSuffix}", 'zlib', 'dbus-1')) { + if ($DepsPrefixDir -ne $PrefixDir) { + Copy-Item -Path (Join-Path $DepsPrefixDir bin "${x}.dll") -Destination (Join-Path $PrefixDir bin) + } + Copy-Item -Path (Join-Path $DepsPrefixDir bin "${x}.pdb") -Destination $DebugSymbolsDir + } + + foreach ($x in @('Core', 'DBus', 'Gui', 'Network', 'Widgets', 'WinExtras')) { + if ($DepsPrefixDir -ne $PrefixDir) { + Copy-Item -Path (Join-Path $DepsPrefixDir bin "Qt5${x}.dll") -Destination (Join-Path $PrefixDir bin) + } + Copy-Item -Path (Join-Path $DepsPrefixDir bin "Qt5${x}.pdb") -Destination $DebugSymbolsDir + } + + if ($DepsPrefixDir -ne $PrefixDir) { + New-Item -Path (Join-Path $PrefixDir plugins platforms) -ItemType Directory -ErrorAction Ignore | Out-Null + Copy-Item -Path (Join-Path $DepsPrefixDir plugins platforms qwindows.dll) -Destination (Join-Path $PrefixDir plugins platforms) + } + Copy-Item -Path (Join-Path $DepsPrefixDir plugins platforms qwindows.pdb) -Destination $DebugSymbolsDir + + if ($DepsPrefixDir -ne $PrefixDir) { + New-Item -Path (Join-Path $PrefixDir plugins styles) -ItemType Directory -ErrorAction Ignore | Out-Null + Copy-Item -Path (Join-Path $DepsPrefixDir plugins styles qwindowsvistastyle.dll) -Destination (Join-Path $PrefixDir plugins styles) + } + Copy-Item -Path (Join-Path $DepsPrefixDir plugins styles qwindowsvistastyle.pdb) -Destination $DebugSymbolsDir + + if ($DepsPrefixDir -ne $PrefixDir) { + Copy-Item -Path (Join-Path $DepsPrefixDir translations) -Destination $PrefixDir -Recurse + } + + Invoke-VcEnvCommand cmake --build $BuildDir --target pack-msi + + New-Item -Path $ArtifactsDir -ItemType Directory -ErrorAction Ignore | Out-Null + $MsiPackage = (Get-ChildItem (Join-Path $BuildDir dist msi 'transmission-*.msi'))[0] + Move-Item -Path $MsiPackage.FullName -Destination $ArtifactsDir + Invoke-NativeCommand cmake -E chdir $DebugSymbolsDir 7z a -y (Join-Path $ArtifactsDir "$($MsiPackage.BaseName)-pdb.zip") +} + +function global:Test-Transmission([string] $DepsPrefixDir, [string] $SourceDir) { + $BuildDir = Join-Path $SourceDir .build + + $env:PATH = @( + (Join-Path $DepsPrefixDir bin) + $env:PATH + ) -join [System.IO.Path]::PathSeparator + + try { + Invoke-VcEnvCommand cmake -E chdir $BuildDir ctest -T Test --output-on-failure + } finally { + Publish-CTestResults (Join-Path $BuildDir Testing '*' Test.xml) + } +} diff --git a/release/windows/build-zlib.ps1 b/release/windows/build-zlib.ps1 new file mode 100644 index 000000000..4f53d1527 --- /dev/null +++ b/release/windows/build-zlib.ps1 @@ -0,0 +1,22 @@ +#!/usr/bin/env pwsh + +$global:ZlibVersion = '1.2.11' + +$global:ZlibDeps = @() + +function global:Build-Zlib([string] $PrefixDir, [string] $Arch, [string] $DepsPrefixDir) { + $Filename = "zlib-${ZlibVersion}.tar.gz" + $Url = "https://zlib.net/fossils/${Filename}" + + $SourceDir = Invoke-DownloadAndUnpack $Url $Filename + $BuildDir = Join-Path $SourceDir .build + + $ConfigOptions = @( + '-DCMAKE_BUILD_TYPE=RelWithDebInfo' + "-DCMAKE_INSTALL_PREFIX=${PrefixDir}" + "-DCMAKE_PREFIX_PATH=${DepsPrefixDir}" + ) + + Invoke-CMakeBuildAndInstall $SourceDir $BuildDir $ConfigOptions + Copy-Item -Path (Join-Path $BuildDir zlib.pdb) -Destination (Join-Path $PrefixDir bin) +} diff --git a/release/windows/main.ps1 b/release/windows/main.ps1 new file mode 100644 index 000000000..3f40796d1 --- /dev/null +++ b/release/windows/main.ps1 @@ -0,0 +1,255 @@ +#!/usr/bin/env pwsh + +Param( + [Parameter(Mandatory=$true)] + [ValidateSet('Build', 'Test')] + [string] $Mode, + + [Parameter(Mandatory=$true)] + [ValidateSet('x86', 'x64')] + [string] $BuildArch, + + [Parameter()] + [string] $SourceDir, + + [Parameter()] + [string] $RootDir, + + [Parameter()] + [string] $ScriptBaseUrl +) + +Set-StrictMode -Version '3.0' + +$ErrorActionPreference = 'Stop' +$PSDefaultParameterValues['*:ErrorAction'] = $ErrorActionPreference + +$ScriptDir = Split-Path -Path $PSCommandPath -Parent + +if (-not $RootDir) { + $RootDir = (Get-Item $ScriptDir).Root.Name +} + +$CacheDir = Join-Path $RootDir "${BuildArch}-cache" +$TempDir = Join-Path $RootDir "${BuildArch}-temp" +$PrefixDir = Join-Path $RootDir "${BuildArch}-prefix" + +function Invoke-NativeCommand() { + $Command = $Args[0] + $CommandArgs = @() + if ($Args.Count -gt 1) { + $CommandArgs = $Args[1..($Args.Count - 1)] + } + + Write-Debug "Executing native command: $Command $CommandArgs" + & $Command $CommandArgs + $Result = $LastExitCode + + if ($Result -ne 0) { + throw "$Command $CommandArgs exited with code $Result." + } +} + +function Invoke-Download([string] $Url, [string] $OutFile) { + if (-not (Test-Path $OutFile)) { + Write-Information "Downloading ${Url} to ${OutFile}" -InformationAction Continue + $OldProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri $Url -OutFile $OutFile + $ProgressPreference = $OldProgressPreference + } +} + +function Invoke-DownloadAndUnpack([string] $Url, [string] $Filename, [string[]] $MoreFlags = @()) { + New-Item -Path $CacheDir -ItemType Directory -ErrorAction Ignore | Out-Null + $ArchivePath = Join-Path $CacheDir $Filename + Invoke-Download $Url $ArchivePath + + if ($ArchivePath -match '^(.+)(\.(gz|bz2|xz))$') { + $SubArchivePath = $Matches[1] + if (-not (Test-Path $SubArchivePath)) { + Write-Information "Unpacking archive ${ArchivePath} to ${CacheDir}" -InformationAction Continue + Invoke-NativeCommand 7z x -y $ArchivePath "-o${CacheDir}" | Out-Host + } + $ArchivePath = $SubArchivePath + } + + if ($ArchivePath -match '^(.+)(\.(tar|zip))$') { + $FinalArchivePath = Join-Path $TempDir (Split-Path -Path $Matches[1] -Leaf) + + New-Item -Path $TempDir -ItemType Directory -ErrorAction Ignore | Out-Null + Push-Location -Path $TempDir + + Write-Information "Unpacking archive ${ArchivePath} to ${TempDir}" -InformationAction Continue + Invoke-NativeCommand 7z x -y $ArchivePath @MoreFlags | Out-Host + $ArchivePath = $FinalArchivePath + + Pop-Location + } else { + throw "Archive type is not supported: ${ArchivePath}" + } + + return $ArchivePath +} + +function Invoke-DownloadAndInclude([string] $Uri, [string] $ScriptFile) { + Invoke-Download $Uri $ScriptFile + . $ScriptFile +} + +function Edit-TextFile([string] $PatchedFile, [string] $MatchPattern, [string] $ReplacementString) { + (Get-Content $PatchedFile) -Replace $MatchPattern, $ReplacementString | Out-File "${PatchedFile}_new" -Encoding ascii + Move-Item -Path "${PatchedFile}_new" -Destination $PatchedFile -Force +} + +function Invoke-VcEnvCommand() { + $VcEnvScript = Join-Path $TempDir vcenv.cmd + + if (-not (Test-Path $VcEnvScript)) { + New-Item -Path $TempDir -ItemType Directory -ErrorAction Ignore | Out-Null + Set-Content $VcEnvScript @" + @pushd . + @call "${VcVarsScript}" ${BuildArch} || exit /b 1 + @popd + @%* 2>&1 +"@ + } + + Invoke-NativeCommand $VcEnvScript @args +} + +function Get-StringHash([string] $String, [string] $HashName = 'sha1') +{ + $StringBuilder = New-Object Text.StringBuilder + [System.Security.Cryptography.HashAlgorithm]::Create($HashName).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ` + ForEach-Object { [void] $StringBuilder.Append($_.ToString('x2')) } + return $StringBuilder.ToString() +} + +function Invoke-CMakeBuildAndInstall([string] $SourceDir, [string] $BuildDir, [string[]] $ConfigOptions) { + Invoke-VcEnvCommand cmake -S $SourceDir -B $BuildDir -G Ninja @ConfigOptions + Invoke-VcEnvCommand cmake --build $BuildDir + Invoke-VcEnvCommand cmake --build $BuildDir --target install +} + +function Publish-CTestResults([string] $ReportXmlFilesMask) { + if ($env:APPVEYOR_URL) { + $CTestToJUnit = New-Object System.Xml.Xsl.XslCompiledTransform + $CTestToJUnit.Load("https://raw.githubusercontent.com/rpavlik/jenkins-ctest-plugin/master/ctest-to-junit.xsl") + $WebClient = New-Object System.Net.WebClient + foreach ($ReportXmlFile in (Get-ChildItem $ReportXmlFilesMask)) { + $CTestToJUnit.Transform($ReportXmlFile.FullName, "$($ReportXmlFile.FullName).junit.xml") + $WebClient.UploadFile("${env:APPVEYOR_URL}/api/testresults/junit/${env:APPVEYOR_JOB_ID}", "$($ReportXmlFile.FullName).junit.xml") + } + } +} + +function Import-Script([string] $Name) { + $ScriptFile = Join-Path $ScriptDir "$($Name.ToLower()).ps1" + Invoke-DownloadAndInclude "${ScriptBaseUrl}/$($Name.ToLower()).ps1" $ScriptFile + Set-Variable -Name "$($Name -replace '\W+', '')ScriptFileHash" -Value (Get-StringHash (Get-Content -Path $ScriptFile)) -Scope Global +} + +function Invoke-Build([string] $Name, [switch] $NoCache = $false, [string[]] $MoreArguments = @()) { + Import-Script "Build-${Name}" + + if (-not $NoCache) { + $BuildScriptFileHash = Get-Variable -Name "Build${Name}ScriptFileHash" -ValueOnly + $BuildVersion = Get-Variable -Name "${Name}Version" -ValueOnly + $BuildDeps = Get-Variable -Name "${Name}Deps" -ValueOnly + + $CacheArchiveDeps = @( + "$($Name.ToLower()):${BuildScriptFileHash}" + "toolchain:${ToolchainScriptFileHash}" + ) + $BuildDeps | ` + ForEach-Object { $CacheArchiveDeps += "$($_.ToLower()):$(Get-Variable -Name "Build$($_)ScriptFileHash" -ValueOnly)" } + $CacheArchiveDepsString = ($CacheArchiveDeps | Sort-Object) -join ' ' + $CacheArchiveDepsHash = Get-StringHash $CacheArchiveDepsString + + $CacheArchiveName = "$($Name.ToLower())_${BuildVersion}-vs_${VsVersion}-${BuildArch}-${CacheArchiveDepsHash}.7z" + $CacheArchive = Join-Path $CacheDir $CacheArchiveName + + Write-Information "Cache archive: ${CacheArchiveName} (${CacheArchiveDepsString})" -InformationAction Continue + } else { + $CacheArchiveName = $null + $CacheArchive = $null + } + + while (-not $CacheArchive -or -not (Test-Path $CacheArchive)) { + if ($CacheArchive -and $env:AWS_S3_BUCKET_NAME) { + try { + Write-Information "Downloading cache archive ${CacheArchiveName} from S3" -InformationAction Continue + Invoke-NativeCommand aws s3 cp "s3://${env:AWS_S3_BUCKET_NAME}/windows/${CacheArchiveName}" $CacheArchive + break + } catch { + Write-Warning "Cache archive ${CacheArchiveName} download from S3 failed" + } + } + + $Builder = (Get-Command "Build-${Name}" -CommandType Function).ScriptBlock + + $TempPrefixDir = Join-Path $TempDir "${Name}-Prefix" + $BuilderArguments = @($TempPrefixDir, $BuildArch, $PrefixDir) + $MoreArguments + Write-Information "Running build for ${Name}" -InformationAction Continue + Invoke-Command -ScriptBlock $Builder -ArgumentList $BuilderArguments + + if ($CacheArchive) { + Write-Information "Packing cache archive ${CacheArchive} from ${TempPrefixDir}" -InformationAction Continue + Invoke-NativeCommand cmake -E chdir $TempPrefixDir 7z a -t7z -m0=lzma -mx=9 -y $CacheArchive + + if ($CacheArchive -and $env:AWS_S3_BUCKET_NAME) { + try { + Write-Information "Uploading cache archive ${CacheArchiveName} to S3" -InformationAction Continue + Invoke-NativeCommand aws s3 cp $CacheArchive "s3://${env:AWS_S3_BUCKET_NAME}/windows/${CacheArchiveName}" ` + --metadata "build-deps=${CacheArchiveDepsString}" + } catch { + Write-Warning "Cache archive ${CacheArchiveName} upload to S3 failed" + } + } + } + + break + } + + if ($CacheArchive) { + Write-Information "Unpacking cache archive ${CacheArchive} to ${PrefixDir}" -InformationAction Continue + Invoke-NativeCommand 7z x -y $CacheArchive "-o${PrefixDir}" + } +} + +function Invoke-Test([string] $Name, [string[]] $MoreArguments = @()) { + Import-Script "Build-${Name}" + + $Tester = (Get-Command "Test-${Name}" -CommandType Function).ScriptBlock + + Write-Information "Running test for ${Name}" -InformationAction Continue + Invoke-Command -ScriptBlock $Tester -ArgumentList $MoreArguments +} + +[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 + +if (-not $SourceDir) { + $SourceDir = (Get-Item $ScriptDir).Parent.Parent.FullName +} + +if ($Mode -eq 'Build') { + Import-Script Toolchain + + $env:CFLAGS = $CompilerFlags -join ' ' + $env:CXXFLAGS = $CompilerFlags -join ' ' + $env:LDFLAGS = $LinkerFlags -join ' ' + + Invoke-Build Expat + Invoke-Build DBus + Invoke-Build Zlib + Invoke-Build OpenSsl + Invoke-Build Curl + Invoke-Build Qt + + Invoke-Build Transmission -NoCache -MoreArguments @($SourceDir, $SourceDir) +} + +if ($Mode -eq 'Test') { + Invoke-Test Transmission -MoreArguments @($PrefixDir, $SourceDir) +} diff --git a/release/windows/toolchain.ps1 b/release/windows/toolchain.ps1 new file mode 100644 index 000000000..1dd03bbeb --- /dev/null +++ b/release/windows/toolchain.ps1 @@ -0,0 +1,17 @@ +#!/usr/bin/env pwsh + +$global:CompilerFlags = @( + '/FS' +) + +$global:LinkerFlags = @( + '/LTCG' + '/INCREMENTAL:NO' + '/OPT:REF' + '/DEBUG' + '/PDBALTPATH:%_PDB%' +) + +$global:VsInstallPrefix = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio' 2019 Community +$global:VsVersion = ((& (Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio' Installer vswhere) -Property catalog_productSemanticVersion -Path $VsInstallPrefix) -Split '[+]')[0] +$global:VcVarsScript = Join-Path $VsInstallPrefix VC Auxiliary Build vcvarsall.bat