Skip to content

Commit 006cec1

Browse files
committed
0.17.0: the general library for build programs, the resolved toolset in deps-vcpkg and deps-cmake, and a test kit for plugins (mcpp#734)
- L2, `plugins-core` (renamed from `surface`, which is kept as an alias until 2027-03-28): `mcpp.plugins.declare`, the new `mcpp.plugins.toolset`, which turns the engine's build information into how a toolset reaches a foreign build system (`instance`, `chain`, `detected`), and the new `mcpp.plugins.fs`, which takes `write_if_changed` and the placement helpers from `mcpp.deps`. `plugins-testing` adds `mcpp.plugins.testing`. - deps-vcpkg builds the ports with the toolset mcpp resolved. A Visual Studio instance is selected with VCPKG_VISUAL_STUDIO_PATH and the standard triplet; any other toolset is named in a derived triplet `<base>-mcpp-<hash>` whose text and chain-loaded toolchain hold no path, with the derived triplet as the host triplet and a kept PATH on the MSVC ABI. An MSBuild port under `chain` is refused by name. The C runtime follows the program's contract, and a project triplet that contradicts it is refused naming both statements. - deps-cmake: the Visual Studio generator pointed at the instance, or Ninja with mcpp's ninja and the named tools; CMAKE_MSVC_RUNTIME_LIBRARY follows the program; one build directory per toolset statement. - Compatibility units under `compat/` (`toolset = detected`, the 0.16.0 names in `mcpp::deps`), and a CI check that fails once a unit's date has passed. - `[package] mcpp = ">=2026.9.28.3"`. - Tests: `tests/plugin-logic` (14 cases on stated contexts, every host), the C runtime leg on the Visual Studio row, and a Windows job with Visual Studio masked and the managed toolset: a CMake port, a CMake subproject, a make port (icu) and the MSBuild refusal (libusb).
1 parent 8e0362d commit 006cec1

29 files changed

Lines changed: 2244 additions & 296 deletions
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env bash
2+
# Compatibility units retire themselves (mcpp#734, design §3.7).
3+
#
4+
# A compatibility unit keeps a behaviour for six months after the release that
5+
# replaced it. Its header states the date:
6+
#
7+
# // COMPATIBILITY UNIT (# COMPATIBILITY UNIT in mcpp.toml)
8+
# // retires: 2027-03-28
9+
#
10+
# This check lists every unit and fails when one is past its date, so that a
11+
# deferral cannot outlive its reason unnoticed. Every file under a `compat/`
12+
# directory must carry the header; a file there without one is reported, which
13+
# keeps the list from being empty because the marker was misspelt.
14+
#
15+
# bash .github/scripts/check-compat-retirement.sh
16+
# COMPAT_TODAY=2027-03-29 bash .github/scripts/check-compat-retirement.sh # the failure, on demand
17+
set -euo pipefail
18+
cd "$(dirname "$0")/../.."
19+
20+
today="${COMPAT_TODAY:-$(date -u +%Y-%m-%d)}"
21+
fail=0
22+
units=0
23+
24+
# Every file under a compat/ directory, outside build outputs and fixtures.
25+
while IFS= read -r f; do
26+
grep -qE '^(//|#) COMPATIBILITY UNIT$' "$f" || { echo "FAIL: $f is under compat/ and has no COMPATIBILITY UNIT header"; fail=1; }
27+
done < <(find . -path ./tests -prune -o -path '*/target' -prune -o -path '*/compat/*' -type f -print | sort)
28+
29+
# Every header, wherever it is: its retirement date.
30+
while IFS=$'\t' read -r file date; do
31+
units=$((units + 1))
32+
if [ -z "$date" ]; then
33+
echo "FAIL: $file: a COMPATIBILITY UNIT without a 'retires:' date"
34+
fail=1
35+
elif [[ "$today" > "$date" ]]; then
36+
echo "FAIL: $file: retired on $date (today is $today); remove the unit and what it keeps"
37+
fail=1
38+
else
39+
echo "ok: $file retires on $date"
40+
fi
41+
done < <(find . -path ./tests -prune -o -path '*/target' -prune -o -path ./.git -prune -o \
42+
\( -name '*.cppm' -o -name 'mcpp.toml' \) -type f -print | sort |
43+
xargs awk '
44+
/^(\/\/|#) COMPATIBILITY UNIT$/ { if (pending) print FILENAME "\t"; pending = 1; next }
45+
pending && /retires:/ { match($0, /[0-9]{4}-[0-9]{2}-[0-9]{2}/);
46+
print FILENAME "\t" substr($0, RSTART, RLENGTH); pending = 0 }
47+
ENDFILE { if (pending) print FILENAME "\t"; pending = 0 }')
48+
49+
[ "$units" -gt 0 ] || { echo "FAIL: no COMPATIBILITY UNIT header found"; fail=1; }
50+
echo "$units compatibility unit(s)"
51+
exit "$fail"

‎.github/scripts/check-deps-and-qt.sh‎

Lines changed: 146 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,22 @@ vcpkg_consumer() {
7070
fail "share/fmt/copyright was not deployed beside the program"
7171
echo "ok: a file of the prefix is deployed beside the program"
7272

73+
# THE MECHANISM (0.17.0). On the Visual Studio row the instance mcpp
74+
# resolved is selected and the standard triplet is used, so the ABI hash is
75+
# the one vcpkg computes by itself; on the other rows a derived triplet
76+
# names the resolved tools.
77+
if is_windows; then
78+
grep -rqs 'VCPKG_VISUAL_STUDIO_PATH=' target --include=build.ninja ||
79+
fail "the installation does not select the Visual Studio instance mcpp resolved"
80+
[ -d target/vcpkg_installed/x64-windows/x64-windows ] || fail "the instance mechanism did not use x64-windows"
81+
echo "ok: the installation selects the Visual Studio instance and keeps the standard triplet"
82+
else
83+
ls -d target/vcpkg_installed/*-mcpp-*/*-mcpp-* > /dev/null 2>&1 ||
84+
fail "no derived <base>-mcpp-<hash> prefix under target/vcpkg_installed"
85+
grep -rqs 'MCPP_VCPKG_CXX=' target --include=build.ninja || fail "the installation does not hand vcpkg the resolved compiler"
86+
echo "ok: the installation names the resolved compiler in a derived triplet"
87+
fi
88+
7389
if is_windows; then
7490
# The pack collects it from the runtime search directory.
7591
ls target/vcpkg_installed/x64-windows/x64-windows/bin/fmt.dll > /dev/null || fail "x64-windows built no fmt.dll"
@@ -84,29 +100,34 @@ vcpkg_consumer() {
84100
}
85101

86102
# LINUX UNDER A libc++ TOOLCHAIN. The host compiler vcpkg and CMake find uses
87-
# libstdc++, whose `std::` symbols a libc++ program cannot link. The default
88-
# triplet is then the generated `x64-linux-libcxx`, whose ports build with
89-
# mcpp's clang; fmt's interface returns `std::string`, so the link itself is the
90-
# criterion. The prefix is then shown to survive the default toolchain's own
91-
# installation, which vcpkg would remove if the two triplets shared one.
103+
# libstdc++, whose `std::` symbols a libc++ program cannot link. The ports
104+
# build with mcpp's clang through a derived triplet `<arch>-linux-mcpp-<hash>`
105+
# (0.17.0; `<arch>-linux-libcxx` before); fmt's interface returns
106+
# `std::string`, so the link itself is the criterion. The prefix is then shown
107+
# to survive the default toolchain's own installation, which vcpkg would remove
108+
# if the two triplets shared one.
92109
vcpkg_libcxx() {
93-
local llvm="${MCPP_LLVM:-llvm@22.1.8}" gen=x64-linux-libcxx
94-
[ "$(uname -m)" = aarch64 ] && gen=arm64-linux-libcxx
110+
local llvm="${MCPP_LLVM:-llvm@22.1.8}" gen
95111
cd "$ROOT/tests/vcpkg-consumer"
96112
rm -rf target vcpkg_installed
97113
mkdir -p target/ci
98114
"$MCPP" build --toolchain "$llvm" 2>&1 | tee target/ci/libcxx-build.log
99115
"$MCPP" run --toolchain "$llvm" | tee target/ci/libcxx-run.log
100116
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/libcxx-run.log || fail "the libc++ program did not print through fmt"
101-
local lib; lib=$(find target/vcpkg_installed -path "*/$gen/$gen/lib/libfmt.a" | head -1)
102-
[ -n "$lib" ] || fail "no $gen prefix with libfmt.a"
117+
local lib; lib=$(find target/vcpkg_installed -path "*-mcpp-*/lib/libfmt.a" | head -1)
118+
[ -n "$lib" ] || fail "no derived <arch>-linux-mcpp-<hash> prefix with libfmt.a"
119+
gen=$(basename "$(dirname "$(dirname "$lib")")")
120+
find target -path '*deps-vcpkg/triplets/*' -name "$gen.cmake" -exec grep -l 'clang' {} + | grep -q . ||
121+
fail "the derived triplet $gen does not record the clang toolset"
103122
grep -q 'std::__1::' <(nm -C "$lib") || fail "$lib is not built against libc++"
104123
echo "ok: under $llvm the ports build with mcpp's clang and the program links them"
105124

106125
"$MCPP" build 2>&1 | tee target/ci/default-build.log
107126
"$MCPP" run | tee target/ci/default-run.log
108127
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/default-run.log || fail "the default toolchain's program did not print through fmt"
109128
[ -f "$lib" ] || fail "the default toolchain's installation removed the $gen prefix"
129+
[ "$(ls -d target/vcpkg_installed/*-mcpp-* | wc -l)" -ge 2 ] ||
130+
fail "the default toolchain did not derive a triplet of its own"
110131
local stamp; stamp=$(find target -path '*deps-vcpkg*' -name "$gen.stamp" | head -1)
111132
[ -n "$stamp" ] || fail "no $gen installation stamp"
112133
touch -r "$stamp" target/ci/before-switch-back
@@ -340,6 +361,116 @@ qt_import_only() {
340361
echo "ok: a package that enables rules-qt only for its module runs no build program and reports nothing"
341362
}
342363

364+
# THE TEST KIT (0.17.0). The deps members' decisions -- which mechanism, which
365+
# triplet, which C runtime -- tested against stated build contexts on every
366+
# host, with nothing installed. The build program is the test; the verdicts
367+
# are counted against the cases the fixture declares.
368+
plugin_logic() {
369+
cd "$ROOT/tests/plugin-logic"
370+
rm -rf target
371+
mkdir -p target/ci
372+
"$MCPP" build > target/ci/build.log 2>&1 || { cat target/ci/build.log; fail "a plugin-logic case failed"; }
373+
local results declared passed
374+
results=$(find target -path '*plugins-testing/results.txt' | head -1)
375+
[ -n "$results" ] || fail "the kit wrote no results.txt"
376+
declared=$(grep -cE '^ \{ "' build.mcpp)
377+
passed=$(grep -c '^PASS ' "$results")
378+
cat "$results"
379+
[ "$declared" -gt 0 ] && [ "$passed" -eq "$declared" ] ||
380+
fail "$passed of $declared declared cases passed"
381+
echo "ok: $passed of $declared plugin-logic cases passed"
382+
}
383+
384+
# WINDOWS, THE PROGRAM'S C RUNTIME (0.17.0). Run on the Visual Studio row. A
385+
# self-contained program links the C runtime statically, so its ports must be
386+
# built against the same one: the default triplet becomes x64-windows-static,
387+
# and a project triplet that says otherwise is refused naming both statements
388+
# (a static library of the other runtime fails the link with /failifmismatch;
389+
# a DLL of it puts a second C++ runtime into the process without a word).
390+
vcpkg_crt() {
391+
is_windows || { echo "skip: the C runtime linkage is an MSVC-ABI question"; return 0; }
392+
local d="$ROOT/tests/.ci-vcpkg-crt"
393+
rm -rf "$d"
394+
cp -r "$ROOT/tests/vcpkg-consumer" "$d"
395+
trap 'rm -rf "$ROOT/tests/.ci-vcpkg-crt"' RETURN
396+
cd "$d"
397+
rm -rf target vcpkg_installed
398+
printf '\n[build]\ncxx_runtime = "self-contained"\n' >> mcpp.toml
399+
mkdir -p target/ci
400+
"$MCPP" build 2>&1 | tee target/ci/static-build.log
401+
"$MCPP" run | tee target/ci/static-run.log
402+
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/static-run.log || fail "the self-contained program did not run"
403+
[ -d target/vcpkg_installed/x64-windows-static/x64-windows-static ] ||
404+
fail "a self-contained program's ports were not installed with x64-windows-static"
405+
! find target -path '*/bin/*' -iname 'fmt.dll' | grep -q . || fail "a self-contained program received fmt.dll"
406+
echo "ok: a self-contained program's ports link the C runtime statically, and the link agrees"
407+
408+
sed -i 's|^ o.libraries = { "fmt" };| o.libraries = { "fmt" };\n o.triplet = "x64-windows";|' build.mcpp
409+
grep -q 'o.triplet = "x64-windows";' build.mcpp || fail "the fixture edit did not apply"
410+
if "$MCPP" build > target/ci/contradiction.log 2>&1; then
411+
cat target/ci/contradiction.log; fail "a triplet contradicting the program's C runtime was accepted"
412+
fi
413+
grep -q "the triplet 'x64-windows' links the C runtime dynamic" target/ci/contradiction.log ||
414+
{ cat target/ci/contradiction.log; fail "the refusal does not name the triplet's linkage"; }
415+
echo "ok: a triplet that contradicts the program's C runtime is refused, naming both statements"
416+
}
417+
418+
# WINDOWS WITHOUT VISUAL STUDIO (0.17.0). Run on the row whose Visual Studio is
419+
# masked, with the managed toolset `$MSVC_MANAGED` (xim:msvc@<version>). The
420+
# toolset is named in a derived triplet: a CMake port (fmt) builds, the program
421+
# links it, and a CMake subproject builds with Ninja and the toolset's cl.exe.
422+
vcpkg_managed() {
423+
: "${MSVC_MANAGED:?MSVC_MANAGED names the managed toolset, e.g. xim:msvc@14.44.35207}"
424+
cd "$ROOT/tests/vcpkg-consumer"
425+
rm -rf target vcpkg_installed
426+
mkdir -p target/ci
427+
"$MCPP" build --toolchain "$MSVC_MANAGED" 2>&1 | tee target/ci/managed-build.log
428+
"$MCPP" run --toolchain "$MSVC_MANAGED" | tee target/ci/managed-run.log
429+
grep -qE '^vcpkg-consumer: fmt [0-9]+ says 42$' target/ci/managed-run.log || fail "the program did not print through fmt"
430+
ls -d target/vcpkg_installed/x64-windows-mcpp-*/x64-windows-mcpp-*/bin/fmt.dll > /dev/null 2>&1 ||
431+
fail "no derived x64-windows-mcpp-<hash> prefix with fmt.dll"
432+
grep -rqs -- '--host-triplet=x64-windows-mcpp-' target --include=build.ninja || fail "the host triplet is not the derived one"
433+
echo "ok: without Visual Studio, a CMake port builds with the managed toolset named in a derived triplet"
434+
435+
cd "$ROOT/tests/cmake-consumer"
436+
rm -rf target
437+
mkdir -p target/ci
438+
"$MCPP" build --toolchain "$MSVC_MANAGED" 2>&1 | tee target/ci/managed-build.log
439+
"$MCPP" run --toolchain "$MSVC_MANAGED" | grep -q '^cmake-consumer: greet says 42$' || fail "the cmake-consumer did not run"
440+
grep -rqs 'CMAKE_GENERATOR:INTERNAL=Ninja' target --include=CMakeCache.txt || fail "the subproject was not configured with Ninja"
441+
grep -rqsi 'CMAKE_CXX_COMPILER:[A-Z]*=.*xim-x-msvc.*cl.exe' target --include=CMakeCache.txt ||
442+
fail "the subproject was not configured with the managed toolset's cl.exe"
443+
echo "ok: without Visual Studio, a CMake subproject builds with Ninja and the managed toolset"
444+
}
445+
446+
# The same row: a port that needs MSBuild is refused by name.
447+
vcpkg_msbuild_refused() {
448+
: "${MSVC_MANAGED:?MSVC_MANAGED names the managed toolset}"
449+
cd "$ROOT/tests/vcpkg-msbuild-port"
450+
rm -rf target
451+
mkdir -p target/ci
452+
if "$MCPP" build --toolchain "$MSVC_MANAGED" > target/ci/build.log 2>&1; then
453+
cat target/ci/build.log; fail "an MSBuild port built without Visual Studio"
454+
fi
455+
grep -q "builds with MSBuild, which needs a Visual Studio instance" target/ci/build.log ||
456+
{ tail -60 target/ci/build.log; fail "the MSBuild port failed without the plugin's reason"; }
457+
echo "ok: an MSBuild port is refused by name without Visual Studio"
458+
}
459+
460+
# The same row: a port that configures with make under msys (icu) finds
461+
# link.exe on the PATH vcpkg keeps.
462+
vcpkg_make_port() {
463+
: "${MSVC_MANAGED:?MSVC_MANAGED names the managed toolset}"
464+
cd "$ROOT/tests/vcpkg-make-port"
465+
rm -rf target
466+
mkdir -p target/ci
467+
"$MCPP" build --toolchain "$MSVC_MANAGED" > target/ci/build.log 2>&1 ||
468+
{ tail -80 target/ci/build.log; fail "the make-based port did not build with the managed toolset"; }
469+
"$MCPP" run --toolchain "$MSVC_MANAGED" | tee target/ci/run.log
470+
grep -qE '^vcpkg-make-port: icu [0-9]' target/ci/run.log || fail "the program did not read icu's version"
471+
echo "ok: a make-based port builds with the managed toolset first on the kept PATH"
472+
}
473+
343474
case "${1:-}" in
344475
vcpkg-consumer) vcpkg_consumer ;;
345476
vcpkg-libcxx) vcpkg_libcxx ;;
@@ -350,5 +481,10 @@ case "${1:-}" in
350481
qt-widgets-consumer) qt_widgets_consumer ;;
351482
qt-sdk-consumer) qt_sdk_consumer ;;
352483
qt-import-only) qt_import_only ;;
353-
*) echo "usage: $0 vcpkg-consumer|vcpkg-libcxx|archive-consumer|vcpkg-workspace|cmake-consumer|qt-consumer|qt-widgets-consumer|qt-sdk-consumer|qt-import-only"; exit 2 ;;
484+
plugin-logic) plugin_logic ;;
485+
vcpkg-crt) vcpkg_crt ;;
486+
vcpkg-managed) vcpkg_managed ;;
487+
vcpkg-msbuild-refused) vcpkg_msbuild_refused ;;
488+
vcpkg-make-port) vcpkg_make_port ;;
489+
*) echo "usage: $0 vcpkg-consumer|vcpkg-libcxx|archive-consumer|vcpkg-workspace|cmake-consumer|qt-consumer|qt-widgets-consumer|qt-sdk-consumer|qt-import-only|plugin-logic|vcpkg-crt|vcpkg-managed|vcpkg-msbuild-refused|vcpkg-make-port"; exit 2 ;;
354490
esac

0 commit comments

Comments
 (0)