Skip to content

Commit 2379484

Browse files
committed
ci: Add Windows cross-build and native test jobs
1 parent 29e7d26 commit 2379484

3 files changed

Lines changed: 257 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,52 @@ jobs:
127127
export PATH="$(brew --prefix llvm)/bin:$PATH"
128128
CI_CONFIG="ci/configs/macos.bash" bash ci/scripts/ci.sh
129129
130+
build-windows-cross:
131+
runs-on: ubuntu-latest
132+
name: build • windows cross
133+
container: debian:trixie
134+
135+
steps:
136+
- uses: actions/checkout@v6
137+
138+
- name: Install dependencies
139+
run: |
140+
apt-get update
141+
apt-get install --no-install-recommends -y \
142+
build-essential \
143+
ca-certificates \
144+
cmake \
145+
curl \
146+
g++-mingw-w64-ucrt64 \
147+
ninja-build \
148+
pkgconf
149+
150+
- name: Build Windows artifacts
151+
run: bash ci/scripts/windows_cross_build.sh
152+
153+
- name: Upload Windows artifacts
154+
uses: actions/upload-artifact@v4
155+
with:
156+
name: windows-cross-ucrt-build
157+
path: windows-cross-artifact
158+
159+
test-windows-cross:
160+
runs-on: windows-latest
161+
name: test • windows cross
162+
needs: build-windows-cross
163+
164+
steps:
165+
- uses: actions/checkout@v6
166+
167+
- name: Download Windows artifacts
168+
uses: actions/download-artifact@v4
169+
with:
170+
name: windows-cross-ucrt-build
171+
path: windows-cross-artifact
172+
173+
- name: Run Windows tests
174+
shell: pwsh
175+
run: ci/scripts/windows_native_test.ps1 -ArtifactRoot windows-cross-artifact
130176
build:
131177
runs-on: ubuntu-latest
132178

ci/scripts/windows_cross_build.sh

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Copyright (c) The Bitcoin Core developers
4+
# Distributed under the MIT software license, see the accompanying
5+
# file COPYING or https://opensource.org/license/mit/.
6+
7+
export LC_ALL=C.UTF-8
8+
9+
set -o errexit -o nounset -o pipefail -o xtrace
10+
11+
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
12+
readonly REPO_DIR="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"
13+
readonly BUILD_ROOT="${REPO_DIR}/build-windows-cross"
14+
readonly ARTIFACT_DIR="${REPO_DIR}/windows-cross-artifact"
15+
readonly CAPNP_VERSION="1.4.0"
16+
readonly TARGET="x86_64-w64-mingw32ucrt"
17+
readonly NATIVE_PREFIX="${BUILD_ROOT}/capnp-native-prefix"
18+
readonly TARGET_PREFIX="${BUILD_ROOT}/capnp-target-prefix"
19+
readonly TOOLCHAIN_FILE="${BUILD_ROOT}/toolchain.cmake"
20+
readonly CAPNP_TARBALL="${BUILD_ROOT}/capnproto-cxx-${CAPNP_VERSION}.tar.gz"
21+
readonly NATIVE_MPGEN_BUILD="${BUILD_ROOT}/project-native-build"
22+
readonly NATIVE_MPGEN="${NATIVE_MPGEN_BUILD}/mpgen"
23+
24+
capnp_source_dir=""
25+
26+
download_capnp_source() {
27+
mkdir -p "${BUILD_ROOT}"
28+
rm -rf "${BUILD_ROOT}/capnproto-src"
29+
curl --fail --location --silent --show-error \
30+
"https://capnproto.org/capnproto-c++-${CAPNP_VERSION}.tar.gz" \
31+
--output "${CAPNP_TARBALL}"
32+
tar -xf "${CAPNP_TARBALL}" -C "${BUILD_ROOT}"
33+
34+
local source_dir
35+
source_dir="$(find "${BUILD_ROOT}" -maxdepth 1 -type d -name 'capnproto-*' | head -n 1)"
36+
[[ -n "${source_dir}" ]] || {
37+
echo "Could not locate extracted Cap'n Proto source tree." >&2
38+
exit 1
39+
}
40+
41+
if [[ -f "${source_dir}/CMakeLists.txt" ]]; then
42+
capnp_source_dir="${source_dir}"
43+
elif [[ -f "${source_dir}/c++/CMakeLists.txt" ]]; then
44+
capnp_source_dir="${source_dir}/c++"
45+
else
46+
echo "Could not locate Cap'n Proto CMakeLists.txt." >&2
47+
exit 1
48+
fi
49+
}
50+
51+
write_toolchain_file() {
52+
mkdir -p "${BUILD_ROOT}"
53+
cat > "${TOOLCHAIN_FILE}" <<EOF
54+
set(CMAKE_SYSTEM_NAME Windows)
55+
set(CMAKE_SYSTEM_VERSION 10.0)
56+
set(CMAKE_C_COMPILER ${TARGET}-gcc)
57+
set(CMAKE_CXX_COMPILER ${TARGET}-g++)
58+
set(CMAKE_RC_COMPILER ${TARGET}-windres)
59+
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
60+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
61+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
62+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
63+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
64+
EOF
65+
}
66+
67+
build_native_capnp() {
68+
cmake -S "${capnp_source_dir}" -B "${BUILD_ROOT}/capnp-native-build" \
69+
-G Ninja \
70+
-DBUILD_SHARED_LIBS=OFF \
71+
-DBUILD_TESTING=OFF \
72+
-DCMAKE_BUILD_TYPE=Release \
73+
-DCMAKE_INSTALL_PREFIX="${NATIVE_PREFIX}" \
74+
-DWITH_OPENSSL=OFF \
75+
-DWITH_ZLIB=OFF
76+
cmake --build "${BUILD_ROOT}/capnp-native-build" --parallel
77+
cmake --install "${BUILD_ROOT}/capnp-native-build"
78+
}
79+
80+
build_target_capnp() {
81+
cmake -S "${capnp_source_dir}" -B "${BUILD_ROOT}/capnp-target-build" \
82+
-G Ninja \
83+
-DBUILD_SHARED_LIBS=OFF \
84+
-DBUILD_TESTING=OFF \
85+
-DCAPNP_EXECUTABLE="${NATIVE_PREFIX}/bin/capnp" \
86+
-DCAPNPC_CXX_EXECUTABLE="${NATIVE_PREFIX}/bin/capnpc-c++" \
87+
-DCMAKE_BUILD_TYPE=Release \
88+
-DCMAKE_INSTALL_PREFIX="${TARGET_PREFIX}" \
89+
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" \
90+
-DWITH_OPENSSL=OFF \
91+
-DWITH_ZLIB=OFF
92+
cmake --build "${BUILD_ROOT}/capnp-target-build" --parallel
93+
cmake --install "${BUILD_ROOT}/capnp-target-build"
94+
}
95+
96+
build_native_mpgen() {
97+
cmake -S "${REPO_DIR}" -B "${NATIVE_MPGEN_BUILD}" \
98+
-G Ninja \
99+
-DCMAKE_BUILD_TYPE=Release \
100+
-DCMAKE_PREFIX_PATH="${NATIVE_PREFIX}"
101+
cmake --build "${NATIVE_MPGEN_BUILD}" -t mpgen --parallel
102+
}
103+
104+
build_project() {
105+
cmake -S "${REPO_DIR}" -B "${BUILD_ROOT}/project-build" \
106+
-G Ninja \
107+
-DCAPNP_EXECUTABLE="${NATIVE_PREFIX}/bin/capnp" \
108+
-DCAPNPC_CXX_EXECUTABLE="${NATIVE_PREFIX}/bin/capnpc-c++" \
109+
-DCMAKE_BUILD_TYPE=Release \
110+
-DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++" \
111+
-DMPGEN_EXECUTABLE="${NATIVE_MPGEN}" \
112+
-DCMAKE_PREFIX_PATH="${TARGET_PREFIX}" \
113+
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}"
114+
cmake --build "${BUILD_ROOT}/project-build" -t all tests mpexamples --parallel
115+
}
116+
117+
copy_artifact_file() {
118+
local src="$1"
119+
local dest="$2"
120+
121+
install -D -m 0755 "${src}" "${ARTIFACT_DIR}/${dest}"
122+
}
123+
124+
copy_runtime_dlls() {
125+
local exe="$1"
126+
local dll
127+
local dll_path
128+
129+
while read -r dll; do
130+
[[ -n "${dll}" ]] || continue
131+
case "${dll}" in
132+
ADVAPI32.dll|COMBASE.dll|COMCTL32.dll|GDI32.dll|KERNEL32.dll|OLE32.dll|OLEAUT32.dll|RPCRT4.dll|SHELL32.dll|UCRTBASE.dll|USER32.dll|WS2_32.dll)
133+
continue
134+
;;
135+
esac
136+
dll_path="$(${TARGET}-g++ -print-file-name="${dll}")"
137+
if [[ "${dll_path}" == "${dll}" || ! -f "${dll_path}" ]]; then
138+
case "${dll}" in
139+
lib*.dll)
140+
echo "Could not locate runtime DLL ${dll}." >&2
141+
exit 1
142+
;;
143+
*)
144+
continue
145+
;;
146+
esac
147+
fi
148+
install -D -m 0755 "${dll_path}" "${ARTIFACT_DIR}/${dll}"
149+
done < <(${TARGET}-objdump -p "${exe}" | awk '/DLL Name: / {print $3}' | sort -u)
150+
}
151+
152+
package_artifacts() {
153+
rm -rf "${ARTIFACT_DIR}"
154+
155+
copy_artifact_file "${BUILD_ROOT}/project-build/test/mptest.exe" "test/mptest.exe"
156+
copy_artifact_file "${BUILD_ROOT}/project-build/example/mpexample.exe" "example/mpexample.exe"
157+
copy_artifact_file "${BUILD_ROOT}/project-build/example/mpcalculator.exe" "example/mpcalculator.exe"
158+
copy_artifact_file "${BUILD_ROOT}/project-build/example/mpprinter.exe" "example/mpprinter.exe"
159+
160+
copy_runtime_dlls "${BUILD_ROOT}/project-build/test/mptest.exe"
161+
copy_runtime_dlls "${BUILD_ROOT}/project-build/example/mpexample.exe"
162+
copy_runtime_dlls "${BUILD_ROOT}/project-build/example/mpcalculator.exe"
163+
copy_runtime_dlls "${BUILD_ROOT}/project-build/example/mpprinter.exe"
164+
}
165+
166+
main() {
167+
rm -rf "${BUILD_ROOT}" "${ARTIFACT_DIR}"
168+
download_capnp_source
169+
write_toolchain_file
170+
build_native_capnp
171+
build_target_capnp
172+
build_native_mpgen
173+
build_project
174+
package_artifacts
175+
}
176+
177+
main "$@"

ci/scripts/windows_native_test.ps1

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright (c) The Bitcoin Core developers
2+
# Distributed under the MIT software license, see the accompanying
3+
# file COPYING or https://opensource.org/license/mit/.
4+
5+
$ErrorActionPreference = "Stop"
6+
7+
param(
8+
[Parameter(Mandatory = $true)]
9+
[string]$ArtifactRoot
10+
)
11+
12+
$artifactPath = (Resolve-Path $ArtifactRoot).Path
13+
$env:PATH = "$artifactPath;$env:PATH"
14+
15+
$mptest = Join-Path $artifactPath "test\mptest.exe"
16+
& $mptest
17+
if ($LASTEXITCODE -ne 0) {
18+
exit $LASTEXITCODE
19+
}
20+
21+
$exampleDir = Join-Path $artifactPath "example"
22+
Push-Location $exampleDir
23+
try {
24+
$output = "2+2`nexit`n" | & ".\mpexample.exe" 2>&1 | Out-String
25+
Write-Host $output
26+
if ($LASTEXITCODE -ne 0) {
27+
exit $LASTEXITCODE
28+
}
29+
if ($output -notmatch "mpprinter:" -or $output -notmatch "Bye!") {
30+
throw "Unexpected mpexample output."
31+
}
32+
} finally {
33+
Pop-Location
34+
}

0 commit comments

Comments
 (0)