From e94c8fa25625b65dbd3ce6b8fdc559c0d9a668d1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 14 Jul 2026 11:02:54 +0200 Subject: [PATCH] msys2-runtime: make local test builds repeatable and incremental Manually reconstructing the required MSYS environment and prerequisite sequence consumed far more time than compiling the runtime. Codify that knowledge so prepared source trees can be rebuilt incrementally while preserving existing build trees and complete logs. Document this workflow in `AGENTS.md`, including why `--cleanbuild` is unsafe when `src` contains retained working source: it deletes the entire directory. Assisted-by: GPT-5.6 Sol Signed-off-by: Johannes Schindelin Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- AGENTS.md | 27 ++- msys2-runtime/test-build-msys2-runtime.sh | 248 ++++++++++++++++++++++ 2 files changed, 270 insertions(+), 5 deletions(-) create mode 100755 msys2-runtime/test-build-msys2-runtime.sh diff --git a/AGENTS.md b/AGENTS.md index 7995850e351..d7b017f723e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,11 +33,28 @@ Do not use `bash -l` or `bash --login`; login shells may hang in Git for Windows SDK environments. Use `makepkg -s` to install missing dependencies automatically. -Use `--nocheck` to skip the test suite, `--cleanbuild` to force a -clean rebuild, and `--skippgpcheck` to skip GPG signature -verification. Use `makepkg -o` (extract and prepare only) to -validate that patches apply cleanly without waiting for a full -compile. +Use `--nocheck` to skip the test suite and `--skippgpcheck` to skip +GPG signature verification. Never use `--cleanbuild` when `src/` +contains a retained playground or other working source tree: it +deletes the entire directory. Use `makepkg -o` (extract and prepare +only) to validate that patches apply cleanly without waiting for a +full compile. + +### Test-building the MSYS2 runtime + +For an already-prepared `msys2-runtime/src/msys2-runtime` source tree, +test-build the runtime DLL without packaging it: + + cd msys2-runtime + ./test-build-msys2-runtime.sh -j15 + +The helper resets inherited MINGW environment variables, selects the +MSYS toolchain, and builds `new-msys-2.0.dll` in a private incremental +build tree under `src/`. Complete logs are written below that build +tree. Use `--reconfigure` after build-system changes, `--full` to +continue with the aggregate build, and `--source-dir` when testing an +external or linked source tree. The helper never cleans or removes an +existing build tree. When a package uses git sources, `updpkgsums` must be run with `core.autoCRLF=false` in the Git configuration. Otherwise the diff --git a/msys2-runtime/test-build-msys2-runtime.sh b/msys2-runtime/test-build-msys2-runtime.sh new file mode 100755 index 00000000000..8c4bb87d368 --- /dev/null +++ b/msys2-runtime/test-build-msys2-runtime.sh @@ -0,0 +1,248 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage () { + cat <<-EOF + usage: $0 [--source-dir ] [--build-dir ] [--full] + [--reconfigure] [-j ] + + Configure and test-build the MSYS2 runtime without deleting any existing + build tree. The default source is src/msys2-runtime next to this script. + The default target is new-msys-2.0.dll. --full continues with the + complete build after the runtime DLL succeeds. --reconfigure forces + autogen and configure even when the cached configuration matches. + EOF +} + +summarize_output () { + sed -n \ + -e '/warning:/p' \ + -e '/error:/p' \ + -e '/\*\*\* \[/p' \ + -e '/new-msys-2\.0\.dll/p' +} + +jobs=${JOBS:-$(nproc)} +source_dir= +build_dir= +full_build= +reconfigure= + +while test $# -gt 0 +do + case "$1" in + --source-dir) + test $# -ge 2 || { + echo "error: --source-dir requires a value" >&2 + exit 2 + } + source_dir=$2 + shift 2 + ;; + --build-dir) + test $# -ge 2 || { + echo "error: --build-dir requires a value" >&2 + exit 2 + } + build_dir=$2 + shift 2 + ;; + --full) + full_build=t + shift + ;; + --reconfigure) + reconfigure=t + shift + ;; + -j|--jobs) + test $# -ge 2 || { + echo "error: $1 requires a value" >&2 + exit 2 + } + jobs=$2 + shift 2 + ;; + -j[0-9]*) + jobs=${1#-j} + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "error: unknown option: $1" >&2 + usage >&2 + exit 2 + ;; + esac +done + +case "$jobs" in +''|*[!0-9]*|0) + echo "error: job count must be a positive integer: $jobs" >&2 + exit 2 + ;; +esac + +package_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) +if test -z "$source_dir" +then + source_dir=$package_dir/src/msys2-runtime +fi +test -d "$source_dir/winsup" || { + echo "error: MSYS2 runtime source not found at $source_dir" >&2 + exit 1 +} +source_dir=$(cd "$source_dir" && pwd -P) + +# PowerShell may have inherited a MINGW64 environment. Reset all related +# variables together; changing MSYSTEM alone leaves stale tool paths behind. +export MSYSTEM=MSYS +. /etc/msystem +export ACLOCAL_PATH=/usr/share/aclocal +export PATH=/usr/bin:/mingw64/bin:/mingw32/bin:$PATH + +gcc=$(command -v gcc) +gcc_target=$(gcc -dumpmachine) +test "$gcc" = /usr/bin/gcc || { + echo "error: expected /usr/bin/gcc, found $gcc" >&2 + exit 1 +} +test "$gcc_target" = "$MSYSTEM_CHOST" || { + echo "error: gcc targets $gcc_target, expected $MSYSTEM_CHOST" >&2 + exit 1 +} + +if test -z "$build_dir" +then + build_dir="$(dirname "$source_dir")/build-test-$MSYSTEM_CHOST" +fi +mkdir -p "$build_dir/logs" +build_dir=$(cd "$build_dir" && pwd -P) + +pkgver=$(sed -n 's/^pkgver=//p' "$package_dir/PKGBUILD") +test -n "$pkgver" || { + echo "error: could not read pkgver from $package_dir/PKGBUILD" >&2 + exit 1 +} + +runtime_commit=$(git -C "$source_dir" rev-parse HEAD) +export CFLAGS="-O2 -pipe -ggdb -DCYGPORT_RELEASE_INFO=$pkgver" +export CXXFLAGS="-O2 -pipe -ggdb" + +config_stamp=$build_dir/.test-build-config +config_key="$MSYSTEM_CHOST|$runtime_commit|$CFLAGS|$CXXFLAGS" +configure_needed=$reconfigure +autogen_needed=$reconfigure + +if ! test -f "$build_dir/Makefile" || ! test -f "$config_stamp" +then + configure_needed=t + test -f "$build_dir/Makefile" || autogen_needed=t +else + test "$(cat "$config_stamp")" = "$config_key" || + configure_needed=t + + build_system_change=$(find "$source_dir/winsup" -type f \ + \( -name configure.ac -o -name Makefile.am -o -name '*.m4' \) \ + -newer "$config_stamp" -print -quit) + if test -n "$build_system_change" + then + autogen_needed=t + configure_needed=t + fi + test "$source_dir/configure" -nt "$build_dir/Makefile" && + configure_needed=t +fi + +timestamp=$(date +%Y%m%d-%H%M%S) +log=$build_dir/logs/build-$timestamp.log + +echo "MSYSTEM=$MSYSTEM" +echo "MSYSTEM_CHOST=$MSYSTEM_CHOST" +echo "gcc=$gcc ($gcc_target)" +echo "source=$source_dir" +echo "build=$build_dir" +echo "log=$log" +if test -n "$configure_needed" +then + echo "configuration=refresh" +else + echo "configuration=reuse" +fi + +{ + if test -n "$autogen_needed" + then + ( + cd "$source_dir/winsup" + ./autogen.sh + ) + fi + + if test -n "$configure_needed" + then + ( + cd "$build_dir" + "$source_dir/configure" \ + --with-msys2-runtime-commit="$runtime_commit" \ + --prefix=/usr \ + --build="$MSYSTEM_CHOST" \ + --sysconfdir=/etc + printf '%s\n' "$config_key" >"$config_stamp" + ) + fi + + ( + cd "$build_dir" + LC_ALL=C make -j"$jobs" all-target-newlib + LC_ALL=C make configure-target-winsup + ) + + LC_ALL=C make \ + -C "$build_dir/$MSYSTEM_CHOST/winsup/cygwin" \ + -j"$jobs" \ + child_info_magic.h \ + shared_info_magic.h \ + globals.h \ + localtime.patched.c + + LC_ALL=C make \ + -C "$build_dir/$MSYSTEM_CHOST/winsup/cygwin" \ + -j"$jobs" \ + new-msys-2.0.dll +} 2>&1 | tee "$log" | summarize_output + +dll=$build_dir/$MSYSTEM_CHOST/winsup/cygwin/new-msys-2.0.dll +test -f "$dll" || { + echo "error: runtime build did not produce $dll" >&2 + exit 1 +} + +newer_source=$(find "$source_dir/winsup/cygwin" -type f \ + \( -name '*.c' -o -name '*.cc' -o -name '*.h' -o -name '*.S' \) \ + -newer "$dll" -print -quit) +test -z "$newer_source" || { + echo "error: runtime DLL is older than $newer_source" >&2 + exit 1 +} + +echo "runtime DLL built successfully: $dll" | tee -a "$log" + +if test -n "$full_build" +then + if ! LC_ALL=C make -C "$build_dir" -j"$jobs" 2>&1 | + tee -a "$log" | + summarize_output + then + echo "error: runtime DLL succeeded, but the full build failed" >&2 + if grep -q 'undefined reference to `ZSTD_' "$log" + then + echo "hint: PKGBUILD lists libzstd-devel as a build dependency" >&2 + fi + exit 1 + fi +fi