Detects mingw-w64/linux-gnu cross compilers and compiles a portability probe with -fsyntax-only to catch narrow-vs-wide API and std::jthread issues before GitHub CI. Skips cleanly when no toolchain is present; --self-test proves dispatch and failure propagation with a fake compiler.
115 lines
2.9 KiB
Bash
115 lines
2.9 KiB
Bash
#!/usr/bin/env bash
|
|
# yams/scripts/local-ci/cross-compile-smoke.sh
|
|
#
|
|
# Compile-only cross-compile smoke lane. Guards on toolchain availability: skips
|
|
# cleanly when no Windows/Linux cross compiler is installed. When one is present,
|
|
# compiles a small portability probe with -fsyntax-only to catch narrow-vs-wide
|
|
# API mismatches, missing std::jthread, and libstdc++ system_clock range
|
|
# differences before they reach GitHub CI.
|
|
#
|
|
# --self-test Prove dispatch and failure propagation with a fake cross compiler.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
PROBE="${SCRIPT_DIR}/portability_probe.cpp"
|
|
|
|
SELF_TEST=0
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--self-test)
|
|
SELF_TEST=1
|
|
shift
|
|
;;
|
|
-h | --help)
|
|
echo "usage: cross-compile-smoke.sh [--self-test]"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "unknown argument: $1" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
detect_cross_compilers() {
|
|
local cxx
|
|
for cxx in x86_64-w64-mingw32-g++ i686-w64-mingw32-g++ aarch64-linux-gnu-g++ x86_64-linux-gnu-g++; do
|
|
if command -v "$cxx" >/dev/null 2>&1; then
|
|
printf '%s\n' "$cxx"
|
|
fi
|
|
done
|
|
}
|
|
|
|
compile_with() {
|
|
local cxx="$1"
|
|
echo "[cross-smoke] compiling probe with ${cxx}"
|
|
if "${cxx}" -std=c++20 -fsyntax-only -I "${REPO_ROOT}/include" "${PROBE}"; then
|
|
echo "[cross-smoke] ${cxx}: ok"
|
|
return 0
|
|
fi
|
|
echo "[cross-smoke] ${cxx}: compile failed" >&2
|
|
return 1
|
|
}
|
|
|
|
scan() {
|
|
local compilers failures=0
|
|
compilers="$(detect_cross_compilers)"
|
|
if [ -z "${compilers}" ]; then
|
|
echo "[cross-smoke] no cross compiler (mingw-w64 / linux-gnu) found; skipping"
|
|
return 0
|
|
fi
|
|
for cxx in ${compilers}; do
|
|
if ! compile_with "${cxx}"; then
|
|
failures=$((failures + 1))
|
|
fi
|
|
done
|
|
return "${failures}"
|
|
}
|
|
|
|
self_test() {
|
|
local tmpdir fake args_log
|
|
tmpdir="$(mktemp -d)"
|
|
args_log="${tmpdir}/args.log"
|
|
fake="${tmpdir}/x86_64-w64-mingw32-g++"
|
|
cat >"${fake}" <<'FAKE'
|
|
#!/usr/bin/env bash
|
|
printf '%s\n' "$@" >>"${YAMS_CROSS_SMOKE_ARGS_LOG:?}"
|
|
exit "${YAMS_CROSS_SMOKE_EXIT:-0}"
|
|
FAKE
|
|
chmod +x "${fake}"
|
|
export PATH="${tmpdir}:${PATH}"
|
|
export YAMS_CROSS_SMOKE_ARGS_LOG="${args_log}"
|
|
|
|
# Dispatch: the fake compiler is detected and receives the expected flags.
|
|
if ! YAMS_CROSS_SMOKE_EXIT=0 scan; then
|
|
echo "[cross-smoke] self-test: dispatch FAILED" >&2
|
|
rm -rf "${tmpdir}"
|
|
return 1
|
|
fi
|
|
for expected in "-fsyntax-only" "-std=c++20" "${REPO_ROOT}/include" "${PROBE}"; do
|
|
if ! grep -qF -- "${expected}" "${args_log}"; then
|
|
echo "[cross-smoke] self-test: missing expected arg ${expected}" >&2
|
|
rm -rf "${tmpdir}"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
# Failure propagation: a failing cross compiler fails the lane.
|
|
if YAMS_CROSS_SMOKE_EXIT=1 scan; then
|
|
echo "[cross-smoke] self-test: failure propagation FAILED" >&2
|
|
rm -rf "${tmpdir}"
|
|
return 1
|
|
fi
|
|
|
|
rm -rf "${tmpdir}"
|
|
echo "[cross-smoke] self-test: dispatch + failure propagation ok"
|
|
return 0
|
|
}
|
|
|
|
if [ "${SELF_TEST}" -eq 1 ]; then
|
|
self_test
|
|
else
|
|
scan
|
|
fi
|