Skip to content

Drop lt12 build path and keep ARM64 workflow lt20-only #51

Drop lt12 build path and keep ARM64 workflow lt20-only

Drop lt12 build path and keep ARM64 workflow lt20-only #51

name: Build Windows ARM64 Native
on:
workflow_dispatch:
push:
branches:
- main
tags:
- 'v*'
permissions:
contents: write
env:
qbt_version: "5.2.3"
qt_version: "6.10.3"
vcpkg_triplet: "arm64-windows-static-release"
jobs:
build-windows-arm64-native:
name: Build Native ARM64 (${{ matrix.libt_variant }})
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- libt_variant: lt20
libt_ref: da7a68a440b7abf4eb1a237df7168be0b8b17084
boost_version: "1.91.0"
libt_version_display: "2.0.13+gitda7a68a440"
archive_suffix: "_lt20"
artifact_name: arm64-native-lt20
env:
boost_root: "${{ github.workspace }}/../boost"
libtorrent_root: "${{ github.workspace }}/../libtorrent-msvc-arm64"
qt_target_root: "${{ github.workspace }}/../qt-msvc-arm64"
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup MSVC cross toolchain
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64_arm64
- name: Install build tools
shell: pwsh
run: |
choco install ninja
- name: Setup vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: '84bab45d415d22042bd0b9081aea57f362da3f35'
vcpkgDirectory: C:/vcpkg
doNotUpdateVcpkg: true
- name: Normalize vcpkg paths
shell: pwsh
run: |
if (-not $env:RUNVCPKG_VCPKG_ROOT) {
throw "RUNVCPKG_VCPKG_ROOT is not set"
}
$vcpkgRoot = $env:RUNVCPKG_VCPKG_ROOT -replace '\\', '/'
"VCPKG_ROOT=$vcpkgRoot" >> $env:GITHUB_ENV
"VCPKG_CMAKE_ROOT=$vcpkgRoot" >> $env:GITHUB_ENV
- name: Install vcpkg dependencies
shell: pwsh
run: |
$packages = @(
"openssl:${{ env.vcpkg_triplet }}",
"zlib:${{ env.vcpkg_triplet }}"
)
& "$env:VCPKG_ROOT/vcpkg.exe" upgrade --no-dry-run
& "$env:VCPKG_ROOT/vcpkg.exe" install --clean-after-build @packages
- name: Build source URLs
shell: pwsh
run: |
$boostVersion = "${{ matrix.boost_version }}"
$boostVersionUnderscored = $boostVersion -replace '\.', '_'
"BOOST_URL=https://archives.boost.io/release/$boostVersion/source/boost_${boostVersionUnderscored}.7z" >> $env:GITHUB_ENV
"QBT_URL=https://github.com/qbittorrent/qBittorrent/archive/refs/tags/release-${{ env.qbt_version }}.tar.gz" >> $env:GITHUB_ENV
- name: Download Boost
shell: pwsh
run: |
aria2c "$env:BOOST_URL" -d "${{ runner.temp }}" -o "boost.7z"
7z x "${{ runner.temp }}/boost.7z" -o"${{ github.workspace }}/.."
Move-Item "${{ github.workspace }}/../boost_*" "${{ env.boost_root }}"
- name: Install Qt host tools
uses: jurplel/install-qt-action@v4
with:
aqtversion: '==3.3.*'
version: "${{ env.qt_version }}"
archives: 'qtbase qttools'
set-env: 'false'
dir: 'C:'
- name: Show tool versions
shell: pwsh
run: |
cmake --version
ninja --version
- name: Build Qt for ARM64
shell: pwsh
run: |
$env:Path = "C:\Qt\${{ env.qt_version }}\msvc2022_64\bin;" + $env:Path
$vcpkgRoot = $env:VCPKG_ROOT
git clone https://github.com/qt/qt5.git qt6
Set-Location qt6
git checkout "v${{ env.qt_version }}"
./configure -init-submodules -submodules qtbase,qtsvg
Remove-Item CMakeCache.txt -ErrorAction SilentlyContinue
./configure -opensource -confirm-license -nomake tests -nomake examples `
-static -static-runtime -release -xplatform win32-arm64-msvc `
-prefix "${{ env.qt_target_root }}" `
-qt-host-path "C:/Qt/${{ env.qt_version }}/msvc2022_64" `
-qt-zlib -schannel -no-openssl -qt-sqlite -sql-sqlite -no-sql-mysql -no-sql-odbc -no-sql-psql -c++std c++20
cmake --build .
cmake --install .
- name: Build libtorrent for ARM64
shell: pwsh
run: |
git init libtorrent
Set-Location libtorrent
git remote add origin https://github.com/arvidn/libtorrent.git
git fetch --depth 1 origin ${{ matrix.libt_ref }}
git checkout FETCH_HEAD
git submodule update --init --recursive --depth 1
$boostRoot = (Get-Item "${{ env.boost_root }}").FullName.Replace('\\', '/')
New-Item -ItemType Directory -Path "${{ env.libtorrent_root }}" -Force | Out-Null
$libtorrentRoot = [System.IO.Path]::GetFullPath("${{ env.libtorrent_root }}").Replace('\\', '/')
$toolchain = "$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
cmake `
-B build `
-G Ninja `
-DCMAKE_BUILD_TYPE=Release `
-DCMAKE_INSTALL_PREFIX="$libtorrentRoot" `
-DCMAKE_TOOLCHAIN_FILE="$toolchain" `
-DBOOST_ROOT="$boostRoot" `
-DBUILD_SHARED_LIBS=OFF `
-Dmmap-disk-io=OFF `
-Ddeprecated-functions=ON `
-Dstatic_runtime=ON `
-DCMAKE_DISABLE_FIND_PACKAGE_OpenSSL=TRUE `
-DVCPKG_TARGET_TRIPLET=${{ env.vcpkg_triplet }}
cmake --build build
cmake --install build
- name: Build qBittorrent for ARM64
shell: pwsh
run: |
$qtTargetRoot = (Get-Item "${{ env.qt_target_root }}").FullName.Replace('\\', '/')
$hostQtRoot = "C:/Qt/${{ env.qt_version }}/msvc2022_64"
$vcpkgInstalled = "$env:VCPKG_ROOT/installed/${{ env.vcpkg_triplet }}"
$boostRoot = (Get-Item "${{ env.boost_root }}").FullName.Replace('\\', '/')
$libtorrentDir = (Get-Item "${{ env.libtorrent_root }}").FullName.Replace('\\', '/') + '/lib/cmake/LibtorrentRasterbar'
$env:Path = "$qtTargetRoot/bin;$env:Path"
aria2c "$env:QBT_URL"
tar -xf "qbittorrent-release-${{ env.qbt_version }}.tar.gz"
Set-Location "qbittorrent-release-${{ env.qbt_version }}"
$qbtSourceDir = (Get-Location).Path
$cmakePreloadFile = Join-Path $qbtSourceDir "ci-preload.cmake"
$commonConfigPath = "cmake/Modules/CommonConfig.cmake"
$commonConfig = Get-Content $commonConfigPath -Raw
$commonConfig = $commonConfig -replace "QT_DISABLE_DEPRECATED_UP_TO=0x060500", "QT_DISABLE_DEPRECATED_UP_TO=0x060A00"
Set-Content $commonConfigPath -Value $commonConfig
$cmakePreload = @(
'find_package(ZLIB REQUIRED)'
'if(TARGET ZLIB::ZLIB)'
' set_property(TARGET ZLIB::ZLIB PROPERTY IMPORTED_GLOBAL TRUE)'
'endif()'
'find_package(OpenSSL REQUIRED)'
'if(TARGET OpenSSL::SSL)'
' set_property(TARGET OpenSSL::SSL PROPERTY IMPORTED_GLOBAL TRUE)'
'endif()'
'if(TARGET OpenSSL::Crypto)'
' set_property(TARGET OpenSSL::Crypto PROPERTY IMPORTED_GLOBAL TRUE)'
'endif()'
) -join "`n"
Set-Content -Path $cmakePreloadFile -Value $cmakePreload
$cmakePreloadPath = (Get-Item $cmakePreloadFile).FullName.Replace('\\', '/')
cmake `
-B build `
-G Ninja `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase `
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="$cmakePreloadPath" `
-DCMAKE_PREFIX_PATH="$qtTargetRoot;$hostQtRoot;$vcpkgInstalled" `
-DQT_HOST_PATH="$hostQtRoot" `
-DCMAKE_FIND_PACKAGE_TARGETS_GLOBAL=ON `
-DOPENSSL_ROOT_DIR="$vcpkgInstalled" `
-DZLIB_ROOT="$vcpkgInstalled" `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" `
-DVCPKG_MANIFEST_MODE=OFF `
-DBOOST_ROOT="$boostRoot" `
-DLibtorrentRasterbar_DIR="$libtorrentDir" `
-DMSVC_RUNTIME_DYNAMIC=OFF `
-DSTACKTRACE=OFF `
-DQT_NO_PRIVATE_MODULE_WARNING=ON `
-DVCPKG_TARGET_TRIPLET=${{ env.vcpkg_triplet }}
cmake --build build
- name: Package artifact
shell: pwsh
run: |
$releaseDir = "release"
$symbolsDir = "symbols"
$artifactDir = "artifact"
$archiveName = "qbittorrent_${{ env.qbt_version }}${{ matrix.archive_suffix }}_arm64.zip"
New-Item -ItemType Directory -Path $releaseDir -Force | Out-Null
New-Item -ItemType Directory -Path $symbolsDir -Force | Out-Null
New-Item -ItemType Directory -Path $artifactDir -Force | Out-Null
Copy-Item "qbittorrent-release-${{ env.qbt_version }}/build/qbittorrent.exe" $releaseDir
Copy-Item "qbittorrent-release-${{ env.qbt_version }}/dist/windows/qt.conf" $releaseDir
$symbols = Get-ChildItem "qbittorrent-release-${{ env.qbt_version }}/build" -Filter "*.pdb" -File -ErrorAction SilentlyContinue
if ($symbols) {
$symbols | Copy-Item -Destination $symbolsDir
}
Set-Location $releaseDir
7z a "../$archiveName" *
Set-Location ..
Move-Item $archiveName $artifactDir
if ((Get-ChildItem $symbolsDir -File -ErrorAction SilentlyContinue).Count -gt 0) {
Move-Item $symbolsDir $artifactDir
}
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact_name }}
path: artifact
smoke-test-windows-arm64-native:
name: Smoke test Native ARM64 (${{ matrix.libt_variant }})
needs: build-windows-arm64-native
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- libt_variant: lt12
artifact_name: arm64-native-lt12
archive_suffix: ""
- libt_variant: lt20
artifact_name: arm64-native-lt20
archive_suffix: "_lt20"
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: ${{ matrix.artifact_name }}
path: artifact
- name: Validate ARM64 qBittorrent artifact
shell: pwsh
run: |
$zipFile = Get-ChildItem artifact -Filter "qbittorrent_*.zip" -File | Select-Object -First 1
if (-not $zipFile) {
throw "No packaged artifact zip found in downloaded build output"
}
$smokeRoot = Join-Path $env:RUNNER_TEMP "qbittorrent-smoke-${{ matrix.libt_variant }}"
New-Item -ItemType Directory -Path $smokeRoot -Force | Out-Null
Expand-Archive -Path $zipFile.FullName -DestinationPath $smokeRoot -Force
$exePath = Join-Path $smokeRoot "qbittorrent.exe"
if (-not (Test-Path $exePath)) {
throw "qbittorrent.exe was not found after extracting the build artifact"
}
$qtConfPath = Join-Path $smokeRoot "qt.conf"
if (-not (Test-Path $qtConfPath)) {
throw "qt.conf was not found after extracting the build artifact"
}
$exeBytes = [System.IO.File]::ReadAllBytes($exePath)
if ($exeBytes.Length -lt 0x40) {
throw "qbittorrent.exe is too small to be a valid PE file"
}
if ($exeBytes[0] -ne 0x4D -or $exeBytes[1] -ne 0x5A) {
throw "qbittorrent.exe is missing the MZ header"
}
$peOffset = [System.BitConverter]::ToInt32($exeBytes, 0x3C)
if ($peOffset -lt 0 -or ($peOffset + 6) -ge $exeBytes.Length) {
throw "qbittorrent.exe has an invalid PE header offset"
}
if ($exeBytes[$peOffset] -ne 0x50 -or $exeBytes[$peOffset + 1] -ne 0x45 -or $exeBytes[$peOffset + 2] -ne 0x00 -or $exeBytes[$peOffset + 3] -ne 0x00) {
throw "qbittorrent.exe is missing the PE signature"
}
$machine = [System.BitConverter]::ToUInt16($exeBytes, $peOffset + 4)
if ($machine -ne 0xAA64) {
throw "Expected ARM64 machine type 0xAA64, got 0x$('{0:X4}' -f $machine)"
}
Write-Host "Artifact validation passed: qbittorrent.exe is ARM64 (machine 0x$('{0:X4}' -f $machine))."
publish-release:
name: Publish release assets
needs: build-windows-arm64-native
if: startsWith(github.ref, 'refs/tags/') || (github.event_name == 'push' && github.ref == 'refs/heads/main')
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Publish tagged release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ env.qbt_version }}
name: qBittorrent ${{ env.qbt_version }} (Windows ARM64 Native)
files: |
artifacts/arm64-native-lt12/qbittorrent_${{ env.qbt_version }}_arm64.zip
artifacts/arm64-native-lt20/qbittorrent_${{ env.qbt_version }}_lt20_arm64.zip
draft: false
prerelease: false
body: |
Native Windows ARM64 builds produced by ci_windows_arm64_native.yaml
Library versions:
- qBittorrent: ${{ env.qbt_version }}
- Qt: ${{ env.qt_version }}
- vcpkg triplet: ${{ env.vcpkg_triplet }}
- libtorrent (lt12): 1.2.20+gitc5ff6c3186
- Boost (lt12): 1.86.0
- libtorrent (lt20): 2.0.13+gitda7a68a440
- Boost (lt20): 1.91.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish branch release
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: softprops/action-gh-release@v2
with:
tag_name: native-arm64-main-${{ github.run_number }}
target_commitish: ${{ github.sha }}
name: qBittorrent native ARM64 main release ${{ github.run_number }}
files: |
artifacts/arm64-native-lt12/qbittorrent_${{ env.qbt_version }}_arm64.zip
artifacts/arm64-native-lt20/qbittorrent_${{ env.qbt_version }}_lt20_arm64.zip
draft: false
prerelease: false
body: |
Native ARM64 builds from branch main.
Commit: ${{ github.sha }}
Library versions:
- qBittorrent: ${{ env.qbt_version }}
- Qt: ${{ env.qt_version }}
- vcpkg triplet: ${{ env.vcpkg_triplet }}
- libtorrent (lt12): 1.2.20+gitc5ff6c3186
- Boost (lt12): 1.86.0
- libtorrent (lt20): 2.0.13+gitda7a68a440
- Boost (lt20): 1.91.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}