Fix Windows CI: alloc_watch MSVC caller-site intrinsic (#51) #108
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================================ | |
| # Laige CI — P0 platform matrix on merge (M0-CI-01) | |
| # | |
| # Roadmap: roadmap/M0-foundations.md, step M0-CI-01 | |
| # PRD refs: §6 (P0 platforms, AC-6.1), §14 (cadence), §8.1 (build budget) | |
| # | |
| # Cadence (PRD §14: "one per PR, all per merge"): | |
| # * this workflow runs on every push to the default branch (master) — | |
| # i.e. on merge — and on manual workflow_dispatch: | |
| # ALL ten jobs run (the five P0 OS/variant jobs, the two sanitizer | |
| # lanes (M0-CI-02), and the three platform-independent tooling jobs: | |
| # the include-graph lint with dependency-count metric (M0-CI-03), | |
| # the public API manifest drift check (M0-TOOL-01), the | |
| # determinism source scan (M1-DET-01), and the determinism check | |
| # (M0-TOOL-02)). | |
| # | |
| # Fuzz lane (PRD §14 "every commit (bounded)"; M0-TEST-01): there is no | |
| # separate fuzz job — the `fuzz_json_parse` ctest entry (1000 | |
| # deterministic runs of laige-fuzz on the json_parse target) runs inside | |
| # every build job's ctest above, instrumented in the ASan tree. Seed and | |
| # nightly-long-run conventions: docs/testing.md. | |
| # * Pull requests run exactly ONE P0 OS (label-selectable, default | |
| # Linux) in the companion workflow .github/workflows/ci-pull.yml. | |
| # | |
| # One job per P0 OS/variant (PRD §6). Each job runs the canonical flow from | |
| # docs/getting-started/building.md — configure → build → ctest (unit tests | |
| # only in M0): | |
| # | |
| # linux-gcc Linux x64, g++ (ubuntu-24.04) | |
| # linux-clang Linux x64, clang++ (ubuntu-24.04) | |
| # linux-asan Linux x64, clang++, LAIGE_ASAN=ON (ubuntu-24.04) | |
| # linux-tsan Linux x64, clang++, LAIGE_TSAN=ON (ubuntu-24.04) | |
| # windows-msvc Windows x64, MSVC 2022 (windows-2022) | |
| # macos-arm64 macOS arm64, AppleClang (macos-15) | |
| # macos-intel macOS Intel, AppleClang (macos-14) | |
| # include-lint Include-graph lint + dependency count (M0-CI-03) | |
| # api-manifest Public API manifest drift check (M0-TOOL-01) | |
| # det-lint Determinism source scan (M1-DET-01) | |
| # detcheck Determinism check (M0-TOOL-02) | |
| # | |
| # The include-lint job (M0-CI-03; NFR-8.11, NFR-8.13) is platform- | |
| # independent — it parses the #include edges of src/** (PRD §10.1 rules: | |
| # laige-core includes nothing internal, arrows only downward in the | |
| # module stack, vendored deps included only from their deps.lock owner) | |
| # and asserts the vendored-dependency count stays ≤ 10 (PRD §11) while | |
| # printing the list. It is Python 3 stdlib only, so one runner image | |
| # suffices; it runs on every PR too (ci-pull.yml, same job definition). | |
| # | |
| # Sanitizer lanes (M0-CI-02; NFR-8.2 "Core is ASan + UBSan + TSan clean in | |
| # CI", AGENTS TEST-006): | |
| # | |
| # * linux-asan builds the canonical build-asan tree (LAIGE_ASAN=ON: | |
| # whole tree instrumented with ASan+UBSan) and runs the unit suites. | |
| # Any sanitizer report is fatal to the test process — UBSan via | |
| # -fno-sanitize-recover=all (wired by CMake), ASan via | |
| # abort_on_error=1:halt_on_error=1 below — so ctest exits non-zero and | |
| # the job fails: "fail build on any sanitizer report". | |
| # * linux-tsan builds the canonical build-tsan tree (LAIGE_TSAN=ON: | |
| # whole tree instrumented with TSan). tests/ applies | |
| # TSAN_OPTIONS=halt_on_error=1 per test (M0-BUILD-01), so the first | |
| # data race report kills the test process and ctest fails. | |
| # | |
| # Toolchain: clang++ for both lanes — TSan is most mature on Clang and | |
| # -fsanitize=undefined enables a superset of the GCC UB checks; the GCC | |
| # build itself is covered by the linux-gcc job. Scope is Linux-only per | |
| # the M0-CI-02 roadmap step (the MSVC/AppleClang sanitizer flag wiring | |
| # already exists in CMake for later extension). | |
| # | |
| # Reports are archived as artifacts on every run, green or red: | |
| # - the tee'd ctest output carries every report that reached stderr | |
| # (ASan and TSan both print reports to stderr); | |
| # - ASan additionally writes one report file per test process under | |
| # asan-reports/ (ASAN_OPTIONS log_path below); | |
| # - <tree>/Testing/Temporary/LastTest.log keeps ctest's full raw | |
| # output of every test. | |
| # | |
| # Build budget (PRD §8.1: clean build ≤ 10 min on CI; roadmap M0-CI-01 | |
| # "matrix runs in < 10 min"): every build job carries timeout-minutes: 10, | |
| # so a job (and therefore the whole matrix, which runs the jobs in | |
| # parallel) longer than the budget fails instead of dragging on. The | |
| # include-lint job is a lint job, not a build, and carries its own | |
| # timeout-minutes: 5. | |
| # | |
| # Windows note: CMake's default generator there is the multi-config | |
| # "Visual Studio 17 2022" generator, which ignores CMAKE_BUILD_TYPE and | |
| # would build every configuration from the canonical `cmake --build build | |
| # -j`. The Windows job therefore pins the canonical Debug configuration | |
| # explicitly on the build and test steps (--config Debug / -C Debug); the | |
| # single-config platforms run the canonical commands verbatim. The | |
| # Windows Test step additionally imports the VS 2022 development | |
| # environment (vswhere + VsDevCmd.bat, same step, before ctest) because | |
| # the trait_compile_* fixtures invoke cl.exe directly from a generated | |
| # cmake -P script — outside the VS generator's toolchain setup — and | |
| # need the MSVC environment (INCLUDE/LIB/PATH) to find the CRT/STL | |
| # headers. | |
| # | |
| # AC-6.1 (same source tree, same feature set, no per-OS feature flags): no | |
| # build job passes feature flags; every build job builds the identical | |
| # tree with the only variation being the platform/compiler (include-lint | |
| # does not build). | |
| # ============================================================================ | |
| name: CI (merge) | |
| on: | |
| push: | |
| branches: [master] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| linux-gcc: | |
| name: Linux x64 (g++) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure | |
| run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++ | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Test (unit) | |
| run: ctest --test-dir build --output-on-failure | |
| linux-clang: | |
| name: Linux x64 (clang++) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure | |
| run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Test (unit) | |
| run: ctest --test-dir build --output-on-failure | |
| linux-asan: | |
| name: Linux x64 ASan+UBSan (clang++) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| # Job-scoped token: the archive step below needs actions:write, which | |
| # the workflow-level contents:read token does not grant (GitHub | |
| # Actions has no step-level permissions). | |
| permissions: | |
| contents: read | |
| actions: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure (ASan+UBSan) | |
| run: cmake -S . -B build-asan -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DLAIGE_ASAN=ON | |
| - name: Build (ASan+UBSan) | |
| run: cmake --build build-asan -j | |
| - name: Test (unit, ASan+UBSan) | |
| # Every sanitizer report is fatal to the test process: ASan via | |
| # abort_on_error=1:halt_on_error=1 here, UBSan via | |
| # -fno-sanitize-recover=all (wired by CMake). detect_leaks=1 (the | |
| # Linux default) is stated explicitly. log_path keeps one report | |
| # file per test process for the artifact upload below. | |
| env: | |
| ASAN_OPTIONS: "abort_on_error=1:halt_on_error=1:detect_leaks=1:log_path=${{ github.workspace }}/asan-reports/asan" | |
| run: | | |
| set -o pipefail | |
| ctest --test-dir build-asan --output-on-failure 2>&1 | tee asan-ctest-output.txt | |
| - name: Archive sanitizer reports | |
| # Runs green or red: on a red run the reports live in this | |
| # artifact. The job-level token grants actions:write. | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-asan-reports | |
| path: | | |
| asan-ctest-output.txt | |
| asan-reports/ | |
| build-asan/Testing/Temporary/LastTest.log | |
| linux-tsan: | |
| name: Linux x64 TSan (clang++) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| # Job-scoped token: the archive step below needs actions:write (see | |
| # the linux-asan job comment). | |
| permissions: | |
| contents: read | |
| actions: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure (TSan) | |
| run: cmake -S . -B build-tsan -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DLAIGE_TSAN=ON | |
| - name: Build (TSan) | |
| run: cmake --build build-tsan -j | |
| - name: Test (unit, TSan) | |
| # TSAN_OPTIONS=halt_on_error=1 is applied per test by tests/ | |
| # (M0-BUILD-01), so the first data race report kills the test | |
| # process and ctest fails. The race report is printed to stderr | |
| # and captured by the tee below. | |
| run: | | |
| set -o pipefail | |
| ctest --test-dir build-tsan --output-on-failure 2>&1 | tee tsan-ctest-output.txt | |
| - name: Archive sanitizer reports | |
| # Runs green or red: on a red run the race report lives in this | |
| # artifact. The job-level token grants actions:write. | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-tsan-reports | |
| path: | | |
| tsan-ctest-output.txt | |
| build-tsan/Testing/Temporary/LastTest.log | |
| windows-msvc: | |
| name: Windows x64 (MSVC 2022) | |
| runs-on: windows-2022 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure | |
| # CMAKE_BUILD_TYPE is ignored by the multi-config VS generator; the | |
| # Debug configuration is pinned on the build/test steps below. | |
| run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug | |
| - name: Build | |
| run: cmake --build build --config Debug -j | |
| - name: Test (unit) | |
| # The trait_compile_* fixtures invoke cl.exe DIRECTLY from a | |
| # generated cmake -P script (execute_process), outside the VS | |
| # generator's toolchain setup, so — unlike every other test in | |
| # this job — they need the MSVC environment (INCLUDE/LIB/PATH) | |
| # to find the CRT/STL headers; the plain runner shell lacks it | |
| # and cl fails with C1083 on <cstdint> etc. This step imports | |
| # the VS development environment into the current PowerShell | |
| # process: vswhere locates the installation, VsDevCmd.bat (the | |
| # canonical vcvars, present in every VS 2017+ install under | |
| # Common7\Tools — called by relative name from that directory, | |
| # so no path quoting is involved) sets it, and its `set` dump | |
| # is imported variable by variable. ctest, cmake -P, and cl all | |
| # inherit it. Everything else in this step is unchanged. | |
| run: | | |
| $vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -property installationPath | |
| Push-Location (Join-Path $vs "Common7\Tools") | |
| $envDump = cmd /c "call VsDevCmd.bat -arch=amd64 -host_arch=amd64 >nul && set" | |
| Pop-Location | |
| foreach ($line in $envDump) { | |
| if ($line -match '^([A-Za-z_][A-Za-z0-9_]*)=(.*)$') { | |
| Set-Item -Path "env:$($matches[1])" -Value $matches[2] | |
| } | |
| } | |
| ctest --test-dir build -C Debug --output-on-failure | |
| macos-arm64: | |
| name: macOS arm64 (AppleClang) | |
| runs-on: macos-15 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure | |
| run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Test (unit) | |
| run: ctest --test-dir build --output-on-failure | |
| macos-intel: | |
| name: macOS Intel (AppleClang) | |
| runs-on: macos-14 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure | |
| run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Test (unit) | |
| run: ctest --test-dir build --output-on-failure | |
| include-lint: | |
| # M0-CI-03 (NFR-8.11, NFR-8.13): platform-independent repository | |
| # check — the include-graph lint over src/** plus the vendored- | |
| # dependency count (budget 10, PRD §11). See the header note. | |
| name: Include-graph lint + dependency count | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Lint include graph + report dependency count | |
| run: python3 tools/laige-include-lint | |
| determinism-lint: | |
| # M1-DET-01: platform-independent repository check — the sim-source | |
| # determinism scan (the second half of the G-R8 guarantee; the first | |
| # is the compile-time trait checked by the trait_compile_* CTest | |
| # fixtures). Forbids raw float/double and unordered containers in | |
| # src/laige-sim/**, with per-line LAIGE-DETERM-EXCEPTION markers as | |
| # the documented false-positive policy (docs/concepts/determinism.md). | |
| # Python 3 stdlib only, so one runner image suffices; it runs on | |
| # every PR too (ci-pull.yml, same job definition). The CTest suite | |
| # runs it against fixture trees and the real tree in every P0 job as | |
| # well (tests/tools, tests `determinism-lint-*`). | |
| name: Determinism source scan (sim module) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Scan sim sources for raw FP / unordered containers | |
| run: python3 tools/laige-determinism-lint | |
| api-manifest: | |
| # M0-TOOL-01 (PRD §9.4, NFR-13.1): the checked-in public API manifest | |
| # (laige-api.json) must stay in sync with the public headers. This | |
| # job regenerates the manifest from the current headers with | |
| # laige-api-scanner and fails on any drift, so adding a public symbol | |
| # without regenerating the manifest fails CI. The CTest suite runs | |
| # the same check against the real tree in every P0 job as well | |
| # (tests/api, test `api-real-tree`). | |
| name: Public API manifest drift | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Configure | |
| run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug | |
| - name: Build scanner | |
| run: cmake --build build --target laige-api-scanner -j | |
| - name: Check manifest drift | |
| run: ./build/bin/laige-api-scanner --root . --check laige-api.json | |
| detcheck: | |
| # M1-DET-04 (FR-11.5; AGENTS ARCH-010, TEST-004): bit-exactness CI. | |
| # The M1-SAMPLE-01 hello scenario is run headless across the | |
| # determinism matrix and asserted for per-tick hash identity: | |
| # | |
| # vs the committed baselines (samples/hello/baselines/; reference | |
| # build: canonical Debug g++) — the P0 OS jobs' ctest already | |
| # runs this half on every platform (tests/sample: | |
| # hello_baseline_fpx / hello_baseline_fp32); this job pins the | |
| # reference build against its own baselines and adds the | |
| # cross-build pairs no single P0 job can produce: | |
| # | |
| # pair A: g++ Debug vs clang++ Debug (the two Linux | |
| # compilers) | |
| # pair B: Debug+ASan vs g++ Release (the two | |
| # configurations) | |
| # | |
| # ... x both SimMath backends (fixed_point_16_16 and | |
| # float_pinned_32 — ADR 0002). A desynced pair is declared | |
| # unsupported for float_pinned_32 (same-build/same-ISA | |
| # scope); fixed_point_16_16 must always match. The result is | |
| # recorded in docs/benchmarks/determinism-matrix.md (scope | |
| # stated per ARCH-010). | |
| # | |
| # Like include-lint and api-manifest, the job runs on every PR and | |
| # merge, independent of the ci:* label selector — it is a tooling | |
| # check, not an additional P0 OS build (the PRD §14 cadence is | |
| # unchanged). | |
| name: Determinism check | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # -- The four build configurations (targeted builds: only the | |
| # scenario binaries and the checker — no full project build). | |
| # The hello binaries land at the SOURCE-tree path | |
| # samples/hello/bin/ (shared across build trees), so each | |
| # tree's binaries are copied into detbin/ immediately after | |
| # that tree is built. | |
| - name: Build reference (Debug g++) | |
| run: | | |
| cmake -S . -B build-det-ref \ | |
| -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++ | |
| cmake --build build-det-ref -j \ | |
| --target hello hello-fp32 laige-detcheck | |
| mkdir -p detbin | |
| cp samples/hello/bin/hello detbin/hello-gcc-debug | |
| cp samples/hello/bin/hello-fp32 detbin/hello-fp32-gcc-debug | |
| cp build-det-ref/bin/laige-detcheck detbin/laige-detcheck | |
| - name: Build clang++ Debug | |
| run: | | |
| cmake -S . -B build-det-clang \ | |
| -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ | |
| cmake --build build-det-clang -j --target hello hello-fp32 | |
| cp samples/hello/bin/hello detbin/hello-clang-debug | |
| cp samples/hello/bin/hello-fp32 detbin/hello-fp32-clang-debug | |
| - name: Build Debug + ASan (clang++) | |
| run: | | |
| cmake -S . -B build-det-asan \ | |
| -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ \ | |
| -DLAIGE_ASAN=ON | |
| cmake --build build-det-asan -j --target hello hello-fp32 | |
| cp samples/hello/bin/hello detbin/hello-asan-debug | |
| cp samples/hello/bin/hello-fp32 detbin/hello-fp32-asan-debug | |
| - name: Build Release (g++) | |
| run: | | |
| cmake -S . -B build-det-release \ | |
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++ | |
| cmake --build build-det-release -j --target hello hello-fp32 | |
| cp samples/hello/bin/hello detbin/hello-gcc-release | |
| cp samples/hello/bin/hello-fp32 detbin/hello-fp32-gcc-release | |
| # -- The reference build must reproduce its own committed baselines | |
| # (a stale baseline is a loud job failure, never a silent | |
| # re-baseline — CORE-008). | |
| - name: Reference baseline sanity | |
| run: | | |
| ./detbin/hello-gcc-debug \ | |
| --expect samples/hello/baselines/fixed_point_16_16/hash_stream.txt | |
| ./detbin/hello-fp32-gcc-debug \ | |
| --expect samples/hello/baselines/float_pinned_32/hash_stream.txt | |
| # -- The checker's built-in synthetic scenario self-check (two | |
| # in-process runs; the M0-TOOL-02 step's Verify clause). | |
| - name: Synthetic scenario self-check | |
| run: ./detbin/laige-detcheck --scenario=synthetic | |
| # -- The two-configuration pairs (the roadmap matrix), both | |
| # backends. Phase 1 spawns the two runs and streams their | |
| # per-tick hash lines into one combined file (the children | |
| # inherit the redirected stdout); phase 2 compares it offline | |
| # (the Windows handle-delivery workaround; this job is | |
| # ubuntu-only, so phase 1 is a plain bash redirection). | |
| - name: Pair A — g++ Debug vs clang++ Debug | |
| run: | | |
| ./detbin/laige-detcheck \ | |
| --run-a=detbin/hello-gcc-debug --run-b=detbin/hello-clang-debug \ | |
| > detbin/combined-a-fpx.txt | |
| ./detbin/laige-detcheck --compare-combined=detbin/combined-a-fpx.txt | |
| ./detbin/laige-detcheck \ | |
| --run-a=detbin/hello-fp32-gcc-debug --run-b=detbin/hello-fp32-clang-debug \ | |
| > detbin/combined-a-fp32.txt | |
| ./detbin/laige-detcheck --compare-combined=detbin/combined-a-fp32.txt | |
| - name: Pair B — Debug+ASan vs Release | |
| run: | | |
| ./detbin/laige-detcheck \ | |
| --run-a=detbin/hello-asan-debug --run-b=detbin/hello-gcc-release \ | |
| > detbin/combined-b-fpx.txt | |
| ./detbin/laige-detcheck --compare-combined=detbin/combined-b-fpx.txt | |
| ./detbin/laige-detcheck \ | |
| --run-a=detbin/hello-fp32-asan-debug --run-b=detbin/hello-fp32-gcc-release \ | |
| > detbin/combined-b-fp32.txt | |
| ./detbin/laige-detcheck --compare-combined=detbin/combined-b-fp32.txt |