deps: openkal 0.5.2 #19
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. | |
| # | |
| # conformance the suite in the specification package runs against this | |
| # implementation and every observation holds | |
| # additions this package's own tests, which examine the operations | |
| # version 0.5 added | |
| # surface the exported names are exactly the fifty-one the | |
| # specification lists, in both forms | |
| # independence the objects reference no C library symbol | |
| # | |
| # The last is the property version 0.5 exists for, and it is asserted against | |
| # the objects rather than against the source, because a source can reach a C | |
| # library through a macro. | |
| # | |
| # Two compiler families, because an implementation is a contract's evidence and | |
| # a contract that holds only under the compiler its author used is a description | |
| # of that compiler. | |
| 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: | |
| conformance: | |
| name: conformance, surface, and independence (${{ matrix.toolchain }}) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolchain: ['gcc@16.1.0', 'llvm@22.1.8'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # The specification is checked out at the branch under test where it has | |
| # one, so that this run asserts what it is for: that the specification as | |
| # written there and this implementation as written here agree today. | |
| - name: The specification | |
| run: | | |
| git clone --quiet https://github.com/mcpplibs/openkal.git .spec | |
| branch='${{ github.head_ref || github.ref_name }}' | |
| if git -C .spec rev-parse --verify --quiet "origin/$branch" > /dev/null; then | |
| git -C .spec checkout --quiet "origin/$branch" | |
| echo "the specification is at $branch" | |
| else | |
| echo "the specification has no $branch; its default branch is used" | |
| fi | |
| - 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: | | |
| xlings update | |
| xlings install "mcpp@$MCPP_VERSION" -y -g | |
| mcpp --version | |
| mcpp self config --mirror GLOBAL | |
| # The compiler family and version for this row. mcpp keeps its toolchains | |
| # in a sandbox of its own, so this selects rather than installs into the | |
| # system, and `mcpp test' and `mcpp run' have no flag for it --- which is | |
| # why it is set once here rather than passed to each command. | |
| - name: Select the toolchain | |
| run: | | |
| spec='${{ matrix.toolchain }}' | |
| case "$spec" in | |
| msvc*) mcpp toolchain default msvc ;; | |
| *) mcpp toolchain install "${spec%@*}" "${spec#*@}" | |
| mcpp toolchain default "$spec" ;; | |
| esac | |
| mcpp toolchain list | |
| - name: Every interface, every kind of examination | |
| run: | | |
| bash .spec/tools/run-conformance.sh openkal-linux . full | |
| - name: Point at the specification's working tree | |
| run: | | |
| # run-conformance.sh has already done this; it is repeated because a | |
| # reader of this file should not have to know that. | |
| sed 's|^openkal = .*$|openkal = { path = ".spec" }|' mcpp.toml > mcpp.toml.next | |
| mv mcpp.toml.next mcpp.toml | |
| - name: This package's own tests | |
| run: | | |
| mcpp test 2>&1 | tee tests.log | |
| # A suite that discovered nothing reports success, so every suite is | |
| # asserted to have run. The list is derived from the files present | |
| # rather than written out here: a hand-written list names the suites | |
| # that existed when it was written, and one added afterwards escapes | |
| # the assertion silently. | |
| missing=0 | |
| for f in tests/*.cpp; do | |
| name="$(basename "$f" .cpp)" | |
| grep -q "^$name \.\.\. ok" tests.log || { echo "did not run or did not pass: $name" >&2; missing=1; } | |
| done | |
| test "$missing" -eq 0 | |
| - name: The exported surface is complete and contains nothing else | |
| run: | | |
| rm -rf target && mcpp build | |
| bash .spec/tools/check-surface.sh --complete .spec/SURFACE.txt \ | |
| $(find target -path '*/obj/*' -name '*.o' ! -name '*.m.o' ! -name 'conformance*' | tr '\n' ' ') | |
| - name: The C++ declarations are complete | |
| run: | | |
| # The specification's own tool examines the C form. The module form is | |
| # examined here, where a build of the modules exists: the test names | |
| # every entity SURFACE.txt lists, so a name the modules do not export | |
| # fails to compile and the diagnostic names it. | |
| list="$(grep -vE '^[[:space:]]*(#|$)' .spec/SURFACE.txt | sort -u)" | |
| { | |
| for m in types abort stream memory env time fs process task; do | |
| echo "import openkal.$m;" | |
| done | |
| echo 'const void *const surface[] = {' | |
| while read -r n; do [ -n "$n" ] && echo " (const void *)&$n,"; done <<< "$list" | |
| echo '};' | |
| echo 'int main() { return surface[0] == 0; }' | |
| } > tests/conformance_declarations.cpp | |
| mcpp test conformance_declarations 2>&1 | tee decl.log | |
| grep -q '^conformance_declarations \.\.\. ok' decl.log | |
| rm -f tests/conformance_declarations.cpp | |
| # The property this version exists for. An implementation beneath a | |
| # program that supplies its own runtime must not reach for that runtime's | |
| # names, or its calls resolve to the program's and recur without bound. | |
| - name: The objects reference no C library symbol | |
| run: | | |
| rm -rf target && mcpp build --features standalone | |
| objs=$(find target -path '*/obj/*' -name '*.o' ! -name '*.m.o' ! -name 'conformance*') | |
| test -n "$objs" || { echo "no objects were found; the check would pass vacuously" >&2; exit 1; } | |
| # The permitted set. memcpy, memmove, memset and memcmp are the four a | |
| # freestanding translation unit is permitted to require: a compiler | |
| # emits calls to them from ordinary loops, and they compute rather | |
| # than call, so none of them can re-enter this implementation. | |
| # __libc_start_main and main are the hand-over, and are undefined here | |
| # by construction. | |
| permitted='^(memcpy|memmove|memset|memcmp|__libc_start_main|main|_GLOBAL_OFFSET_TABLE_|kal_[a-z_]+|__init_array_start|__init_array_end|__preinit_array_start|__preinit_array_end|_ZN3okl.*)$' | |
| bad=0 | |
| for s in $(nm --undefined-only $objs | awk '{print $2}' | sort -u); do | |
| [ -n "$s" ] || continue | |
| if ! printf '%s\n' "$s" | grep -qE "$permitted"; then | |
| echo "the implementation references a symbol it must not: $s" >&2 | |
| bad=1 | |
| fi | |
| done | |
| test "$bad" -eq 0 | |
| echo "the implementation references no C library symbol" | |
| # A checker is only useful if it fails when it should. | |
| - name: The independence check detects a dependence | |
| run: | | |
| printf 'extern "C" int puts(const char*);\nextern "C" void okl_probe(void) { puts("x"); }\n' > src/probe.cpp | |
| rm -rf target && mcpp build --features standalone | |
| objs=$(find target -path '*/obj/*' -name '*.o' ! -name '*.m.o') | |
| if ! nm --undefined-only $objs | awk '{print $2}' | grep -qx puts; then | |
| echo "the probe did not produce the reference it was written to produce" >&2 | |
| rm -f src/probe.cpp; exit 1 | |
| fi | |
| rm -f src/probe.cpp | |
| echo "a dependence upon a C library is visible to the check" |