ci: 安装步骤加重试,一次 xlings update 可能静默返回陈旧索引 #2
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
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| name: the context-switch probe runs | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 40 | |
| env: | |
| MCPP_VERSION: 2026.8.20.2 | |
| XLINGS_VERSION: v2026.8.17.2 | |
| XLINGS_NON_INTERACTIVE: '1' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install xlings | |
| run: | | |
| curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \ | |
| | bash -s "$XLINGS_VERSION" | |
| echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" | |
| - name: Install mcpp | |
| run: | | |
| # ⚠️ A LOOP, BECAUSE ONE `xlings update` CAN RETURN A STALE INDEX | |
| # WITHOUT SAYING SO. | |
| # | |
| # The index is published as an artifact behind a pointer, and that | |
| # pointer propagates asynchronously after a version bump is merged. | |
| # Measured on release day: an update run four minutes after the merge | |
| # printed `index updated`, and the install then failed with | |
| # | |
| # package 'mcpp@<ver>' not found in the synced index | |
| # (xim@artifact:<an older sha>, ...), synced 0 seconds ago | |
| # | |
| # Nothing had gone wrong. The update fetched the PREVIOUS artifact, | |
| # and "synced 0 seconds ago" describes when it was fetched rather than | |
| # what it contains — which is why the message reads as freshness. | |
| # | |
| # So this is not a retry around flakiness; it is the wait that a | |
| # single update does not perform. A pin naming a version that was | |
| # never published still fails, after the last attempt, and says which | |
| # of the two situations it is. | |
| for attempt in 1 2 3 4 5 6; do | |
| xlings update > /dev/null 2>&1 || true | |
| if xlings install "mcpp@$MCPP_VERSION" -y -g; then break; fi | |
| if [ "$attempt" = 6 ]; then | |
| echo "::error::mcpp@$MCPP_VERSION never appeared in the index (6 attempts over 5 minutes). If it was just released, the pointer has not propagated; if the pin names a version that was never published, it never will." | |
| exit 1 | |
| fi | |
| echo "the index has not caught up yet (attempt $attempt of 6); waiting 60s" | |
| sleep 60 | |
| done | |
| mcpp --version | |
| mcpp self config --mirror GLOBAL | |
| - name: Install the emulator | |
| run: | | |
| xlings install xim:qemu-riscv -y | |
| XLINGS_HOME="$HOME/.mcpp/registry" xlings install xim:qemu-riscv -y | |
| - name: The layer builds for riscv64 | |
| run: mcpp build --target riscv64-none-elf | |
| # ⚠️ The probe asserts the CALLEE-SAVED half of the contract, which a | |
| # "does it run" check would miss: a backend that switched stacks but | |
| # dropped s-registers would still print both lines. | |
| - name: The probe switches, returns, and preserves callee-saved registers | |
| run: | | |
| set -euo pipefail | |
| cd examples/switch | |
| mcpp run 2>&1 | tee run.log | |
| grep -q "task: arg=42" run.log | |
| grep -q "witness=7 before=1234" run.log | |
| # --------------------------------------------------------------------------- | |
| # The cross-compilation is performed FROM three systems, not only from Linux. | |
| # | |
| # Every target in this repository is a cross target, which makes the host a | |
| # separate axis from the target: the compiler, the target C library and the | |
| # emulator are payloads mcpp resolves for whichever system it is running on. | |
| # A package that has only ever been built from Linux is a package whose | |
| # consumers must use Linux, and nothing in these sources says so. | |
| # | |
| # ⚠️ A TOOLCHAIN AXIS IS ABSENT HERE, AND THAT IS MEASURED RATHER THAN | |
| # ASSUMED. The row for a bare-metal triple names its compiler, and the | |
| # command-line override does not displace it: `--toolchain gcc@16.1.0` on a | |
| # `riscv64-none-elf` build resolves llvm@22.1.8 regardless. A matrix over | |
| # compiler families would therefore run the same compiler on every row and | |
| # report coverage it does not have. The toolchain axis belongs where the | |
| # choice is real — openkal, whose declarations are compiled by three families | |
| # on three systems. | |
| # | |
| # ⚠️ BUILD ONLY, AND DELIBERATELY. Behaviour is asserted once, above, under an | |
| # emulator. Booting the same image from three systems would be a statement | |
| # about the emulator rather than about this package, and "the image does what | |
| # the README says" does not become more true for having been observed from | |
| # macOS. | |
| portability: | |
| name: cross-builds from ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [macos-14, windows-2022] | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| MCPP_VERSION: 2026.8.20.2 | |
| XLINGS_VERSION: v2026.8.17.2 | |
| XLINGS_NON_INTERACTIVE: '1' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install xlings (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \ | |
| | bash -s "$XLINGS_VERSION" | |
| echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" | |
| - name: Install xlings (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| irm https://d2learn.org/xlings-install.ps1.txt | iex | |
| # The installer amends the user's environment; no later step in this | |
| # job reads it back, so the directory is named here. | |
| "$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| - name: Install mcpp | |
| run: | | |
| # ⚠️ A LOOP, BECAUSE ONE `xlings update` CAN RETURN A STALE INDEX | |
| # WITHOUT SAYING SO. | |
| # | |
| # The index is published as an artifact behind a pointer, and that | |
| # pointer propagates asynchronously after a version bump is merged. | |
| # Measured on release day: an update run four minutes after the merge | |
| # printed `index updated`, and the install then failed with | |
| # | |
| # package 'mcpp@<ver>' not found in the synced index | |
| # (xim@artifact:<an older sha>, ...), synced 0 seconds ago | |
| # | |
| # Nothing had gone wrong. The update fetched the PREVIOUS artifact, | |
| # and "synced 0 seconds ago" describes when it was fetched rather than | |
| # what it contains — which is why the message reads as freshness. | |
| # | |
| # So this is not a retry around flakiness; it is the wait that a | |
| # single update does not perform. A pin naming a version that was | |
| # never published still fails, after the last attempt, and says which | |
| # of the two situations it is. | |
| for attempt in 1 2 3 4 5 6; do | |
| xlings update > /dev/null 2>&1 || true | |
| if xlings install "mcpp@$MCPP_VERSION" -y -g; then break; fi | |
| if [ "$attempt" = 6 ]; then | |
| echo "::error::mcpp@$MCPP_VERSION never appeared in the index (6 attempts over 5 minutes). If it was just released, the pointer has not propagated; if the pin names a version that was never published, it never will." | |
| exit 1 | |
| fi | |
| echo "the index has not caught up yet (attempt $attempt of 6); waiting 60s" | |
| sleep 60 | |
| done | |
| mcpp --version | |
| mcpp self config --mirror GLOBAL | |
| - name: The arch mechanisms cross-build | |
| run: | | |
| mcpp build --target riscv64-none-elf |