Skip to content

bisect: mcpp 2026.8.24.1 #33

bisect: mcpp 2026.8.24.1

bisect: mcpp 2026.8.24.1 #33

Workflow file for this run

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.24.1
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)"
{
# ⚠️ THE MODULE LIST IS DERIVED, NOT WRITTEN OUT.
#
# It used to be written out, and it fell out of step the first time
# the specification gained an interface: SURFACE.txt listed four
# `kal_exec_*' names, no `import openkal.exec' was emitted, and the
# generated test failed with four undeclared identifiers --- which
# names the symptom (a name is missing) and not the cause (a list
# here was not updated).
#
# SURFACE.txt groups its names under `# openkal.<interface>'
# headings, so the list it already carries is the list this needs.
# `types' is not a group there --- it declares no kal_ name --- and
# is therefore named separately.
echo "import openkal.types;"
for m in $(grep -oE '^# openkal\.[a-z]+' .spec/SURFACE.txt | cut -d. -f2); 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"