igneum/proto-cuda/windows-node/cross-build.sh
igneum-labs aed5ca9bd7 Build server adopted: box-first build rule in CLAUDE.md, reproducible Windows exes, the commit-string gate, PC and Mac recipes
Main's decision of 6 October 2026. CLAUDE.md 'Running agents on this Mac': every Linux and Windows cargo build and every
Linux test suite goes to igneum-build-1 through tools/build-remote.sh and tools/cross-remote.sh; the PCs keep GPU and
Windows-runtime jobs; the Mac keeps macOS binaries, the DMG and Metal tests under the lock. -Wl,--no-insert-timestamp in
cross-remote.sh, proto-cuda/windows-node/cross-build.sh and jobbuild.rs (two box builds byte-identical, verified).
The empty-commit class: tools/ci/commit-string-check.sh (self-test in ci.yml, shown firing on a Mac worktree build and
passing on a box build) runs on every igneumd from the three build scripts; push-build-inputs.sh adds node.commit_full,
the PC job writes a minimal node/.git from it at extract and cleans kaspa-build-info on a new commit (4 jobbuild tests
pass, run on the box); cross-build.sh refuses a worktree and cleans on a new commit. Plan: second worktree's clean build
1 min 18 s with sccache 604 hits of 993.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 17:50:39 +00:00

57 lines
5 KiB
Bash
Executable file

#!/usr/bin/env bash
# Cross-compiles igneumd.exe and igneum-miner.exe for x86_64-pc-windows-gnu on the Mac (Homebrew mingw-w64 and llvm).
# Worked on 3 October 2026 (8 min 25 s with -j 6 at nice 19 on a loaded M5 Max); see WINDOWS-MINER.md, "Run your own node".
# What each variable is for:
# CC/CXX/AR_x86_64_pc_windows_gnu the cc crate builds rocksdb (C++), snappy, zstd, lz4, bzip2, zlib, secp256k1 and
# mimalloc with the mingw compilers
# LIBCLANG_PATH librocksdb-sys runs bindgen on rocksdb/c.h; Homebrew llvm's libclang
# BINDGEN_EXTRA_CLANG_ARGS_... bindgen's clang must parse the mingw headers for the Windows target, not the Mac's
# CARGO_TARGET_..._RUSTFLAGS -static: ld takes libstdc++.a, libgcc.a and libwinpthread.a instead of the import
# libraries, so the exe does not need libstdc++-6.dll, libgcc_s_seh-1.dll or
# libwinpthread-1.dll on the PC (the first build linked libstdc++-6.dll because
# -static-libstdc++ means nothing to the gcc driver rustc links with)
# Usage: windows-node/cross-build.sh [node worktree, default vendor/igneum-node-win] [cargo jobs, default 6]
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$HERE/../.." && pwd)"
NODE="${1:-$ROOT/vendor/igneum-node-win}"
JOBS="${2:-6}"
MINGW="/opt/homebrew/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mingw32"
[ -d "$MINGW" ] || { echo "no mingw-w64 at $MINGW (brew install mingw-w64)" >&2; exit 1; }
[ -f /opt/homebrew/opt/llvm/lib/libclang.dylib ] || { echo "no libclang at /opt/homebrew/opt/llvm/lib (brew install llvm)" >&2; exit 1; }
export PATH="$HOME/.cargo/bin:/opt/homebrew/bin:$PATH"
rustup target list --installed | grep -q x86_64-pc-windows-gnu || rustup target add x86_64-pc-windows-gnu
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-target}"
export CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc
export CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++
export AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar
export LIBCLANG_PATH=/opt/homebrew/opt/llvm/lib
export BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu="--target=x86_64-w64-mingw32 --sysroot=$MINGW -I$MINGW/include"
# 5 October 2026 (0.3.7): -static-libstdc++ added as a try; -static alone left libstdc++-6.dll in the import table of
# every exe so far (0.3.5's and the PC's), which is why the payload must ship the DLLs of the toolchain that linked
# the exes (push-inputs.sh takes them from next to the exes first, then from this toolchain) and why push-inputs.sh
# refuses an exe that imports a symbol the shipped DLL does not export.
# 5 October 2026 (housekeeping, after 0.3.8): the fork's database/build.rs now links libstdc++ statically on this
# target (the toolchain's libstdc++.a offered as libstdc++.dll.a in a search dir), so a node built from a fork at or
# after that commit imports no mingw DLL and the pairing rule is moot for it; the gate and the DLL copy stay for any
# older fork. The PC-built exe (GCC 13) died at its first rocksdb call with the dynamic runtime; see the
# release-0.3.6 plan, section 10.
# 6 October 2026 (main's decision): -Wl,--no-insert-timestamp makes the exe reproducible (the PE header timestamp was the one
# byte-level difference between two builds of one tree on igneum-build-1); the box (tools/cross-remote.sh) and the PC job carry it too
export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS="-C link-arg=-static -C link-arg=-static-libgcc -C link-arg=-static-libstdc++ -C link-arg=-Wl,--no-insert-timestamp"
cd "$NODE"
# The commit hash (6 October 2026, found on igneum-build-1): kaspa-build-info's build.rs embeds the commit only when .git is
# a DIRECTORY and HEAD is a symbolic ref to a branch file, and once it has found nothing it emits no rerun-if-changed, so
# cargo never runs it again in this target dir. Two steps: clean that one crate when the commit changed since the last build
# here, and refuse a worktree (.git is a file there: the hash would be empty and tools/ci/commit-string-check.sh would fail
# the release). Build the Windows exes from the fork's main checkout or through tools/cross-remote.sh (the box checks out a branch).
sha=$(git rev-parse HEAD)
[ -d .git ] || { echo "$NODE/.git is not a directory (a worktree): kaspa-build-info would embed no commit; use tools/cross-remote.sh or the fork's main checkout" >&2; exit 1; }
[ "$(cat ".cross-build-sha-$CARGO_TARGET_DIR" 2>/dev/null)" = "$sha" ] || cargo clean -q --release -p kaspa-build-info --target x86_64-pc-windows-gnu 2>/dev/null || true
nice -n 19 cargo build --release -j "$JOBS" -p kaspad -p igneum-miner --features igneum-pow --target x86_64-pc-windows-gnu
echo "$sha" > ".cross-build-sha-$CARGO_TARGET_DIR"
for exe in igneumd igneum-miner; do
f="$CARGO_TARGET_DIR/x86_64-pc-windows-gnu/release/$exe.exe"
echo "$f: $(stat -f %z "$f") bytes; DLLs: $(x86_64-w64-mingw32-objdump -p "$f" | grep 'DLL Name' | awk '{print $3}' | sort -u | tr '\n' ' ')"
[ "$exe" = igneumd ] && "$ROOT/tools/ci/commit-string-check.sh" "$f" "$sha" # only kaspad depends on kaspa-build-info
done