openkal-musl 0.1.0: musl 1.2.5 above openkal, on Linux, macOS and Windows #22
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 | |
| # What this workflow asserts. | |
| # | |
| # The claim this package makes is that a C library ported once onto openkal runs | |
| # above every implementation of the specification, so the claim is tested by | |
| # running the same two programs on three systems and comparing what they produce | |
| # against what the system's own tools produce. | |
| # | |
| # posix a program that opens a file by an absolute name, reads a | |
| # variable, measures an interval, starts another program and waits | |
| # for it --- thirty-two observations, none of which the program | |
| # contains an implementation of | |
| # wordcount the same counts as the system's own `wc' | |
| # | |
| # Two compiler families, gcc and llvm. The third of the three mcpp offers is | |
| # absent from this package and the reason is recorded in the manifest: musl's | |
| # four remaining assembly definitions are in an object format that toolchain | |
| # does not assemble, so the question that toolchain would answer is not one this | |
| # package can ask. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| env: | |
| MCPP_VERSION: 2026.8.19.4 | |
| XLINGS_VERSION: v2026.8.17.2 | |
| XLINGS_NON_INTERACTIVE: '1' | |
| jobs: | |
| programs: | |
| name: ${{ matrix.name }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 90 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { name: 'linux, gcc', os: ubuntu-24.04, toolchain: 'gcc@16.1.0', target: '' } | |
| - { name: 'linux, llvm', os: ubuntu-24.04, toolchain: 'llvm@22.1.8', target: '' } | |
| - { name: 'macos, llvm', os: macos-14, toolchain: 'llvm@20.1.7', target: '' } | |
| - { name: 'windows, gcc', os: windows-2022, toolchain: 'gcc@16.1.0', target: 'x86_64-windows-gnu' } | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: The specification and the implementation for this system | |
| run: | | |
| bash tools/working-trees.sh '${{ github.head_ref || github.ref_name }}' | |
| - 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 | |
| "$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| - name: Install mcpp | |
| run: | | |
| xlings update | |
| xlings install "mcpp@$MCPP_VERSION" -y -g | |
| mcpp --version | |
| mcpp self config --mirror GLOBAL | |
| - name: Select the toolchain | |
| run: | | |
| spec='${{ matrix.toolchain }}' | |
| mcpp toolchain install "${spec%@*}" "${spec#*@}" | |
| mcpp toolchain default "$spec" | |
| mcpp toolchain list | |
| - name: The library builds | |
| run: | | |
| extra='' | |
| [ -n '${{ matrix.target }}' ] && extra='--target ${{ matrix.target }}' | |
| mcpp build $extra | |
| # A program above this package names one package. It does not name | |
| # openkal, it does not name an implementation, and it says nothing about | |
| # the platform. | |
| - name: The posix probe | |
| working-directory: examples/posix | |
| run: | | |
| extra='' | |
| [ -n '${{ matrix.target }}' ] && extra='--target ${{ matrix.target }}' | |
| mcpp build $extra | |
| binary="$(find target -type f \( -name 'posix' -o -name 'posix.exe' \) | head -1)" | |
| # A watchdog, because a program that does not return is as much a | |
| # failure as one that returns wrongly, and the job would otherwise | |
| # spend its whole timeout finding that out. Written out rather than | |
| # taken from `timeout', which two of the three systems have and one | |
| # does not. | |
| watch() { # watch <seconds> <command>... | |
| local seconds="$1"; shift | |
| "$@" & local pid=$! | |
| ( sleep "$seconds"; kill -9 "$pid" 2> /dev/null ) & local guard=$! | |
| wait "$pid"; local status=$? | |
| kill "$guard" 2> /dev/null || true | |
| return $status | |
| } | |
| if watch 120 sh -c "\"$binary\" > run.log 2>&1"; then | |
| cat run.log | |
| else | |
| status=$? | |
| echo "--- what the program printed before it stopped (status $status) ---" | |
| cat run.log | |
| # A program that stopped and a program that did not return need | |
| # different questions asked of them, and "exit code 139" and "the | |
| # job timed out" answer neither. The debugger is for the first; a | |
| # stack sample of a program that is still running is for the second, | |
| # and a debugger asked to run a program that hangs hangs with it. | |
| if [ "$status" -eq 137 ]; then | |
| echo "--- it did not return; where it was ---" | |
| "$binary" > /dev/null 2>&1 & hung=$! | |
| sleep 5 | |
| if command -v sample > /dev/null 2>&1; then | |
| sample "$hung" 3 -mayDie 2>&1 | head -80 || true | |
| elif command -v eu-stack > /dev/null 2>&1; then | |
| eu-stack -p "$hung" 2>&1 | head -60 || true | |
| fi | |
| kill -9 "$hung" 2> /dev/null || true | |
| elif command -v lldb > /dev/null 2>&1; then | |
| watch 90 lldb --batch -o run \ | |
| -k 'thread backtrace all' -k 'register read' -k quit \ | |
| -- "$binary" > crash.log 2>&1 || true | |
| cat crash.log | |
| elif command -v gdb > /dev/null 2>&1; then | |
| watch 90 gdb -batch -ex run -ex 'bt' --args "$binary" > crash.log 2>&1 || true | |
| cat crash.log | |
| fi | |
| exit 1 | |
| fi | |
| # Both directions: that the program reported, and that nothing it | |
| # observed failed to hold. Asserting only the first would pass for a | |
| # program that printed its failures. | |
| grep -qE '^-- failures: 0 --$' run.log | |
| ! grep -q '^FAIL:' run.log | |
| - name: The counts agree with the system's own | |
| working-directory: examples/wordcount | |
| run: | | |
| printf 'alpha beta\ngamma\n' > sample.txt | |
| expected="$(wc < sample.txt | tr -s ' ' | sed 's/^ //')" | |
| extra='' | |
| [ -n '${{ matrix.target }}' ] && extra='--target ${{ matrix.target }}' | |
| mcpp build $extra | |
| binary="$(find target -type f \( -name 'wordcount' -o -name 'wordcount.exe' \) | head -1)" | |
| WORDCOUNT_VERBOSE=1 "$binary" sample.txt 2>&1 | tee run.log | |
| counts="$(sed -n 's/^lines \([0-9]*\) words \([0-9]*\) bytes \([0-9]*\)$/\1 \2 \3/p' run.log)" | |
| test -n "$counts" || { echo "the program printed no count" >&2; exit 1; } | |
| echo "wordcount: $counts" | |
| echo "wc: $expected" | |
| test "$counts" = "$expected" | |
| # The variable was consulted, and the interval was measured. | |
| grep -q 'elapsed .* nanoseconds' run.log |