-
Notifications
You must be signed in to change notification settings - Fork 0
159 lines (146 loc) · 7.31 KB
/
Copy pathci.yml
File metadata and controls
159 lines (146 loc) · 7.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
name: CI
# What this workflow asserts.
#
# conformance the suite in the specification package runs against this
# implementation, on both architectures, and every observation
# holds
# surface the exported names are exactly the fifty-one the
# specification lists
# independence the objects reference nothing of a C library but the two names
# no C library defines
#
# The third is the property version 0.3 exists for. A program above openkal may
# supply every name the system's own library supplies; an implementation that
# called one of them would have its calls resolve to the program's, and the
# program's would resolve back here.
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 (${{ matrix.os }}, ${{ matrix.toolchain }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
# arm64 and x86_64. The system-call numbers agree; the calling
# convention, the register the current context is reached through and
# one field of a signal context do not, so both are built.
- { os: macos-14, toolchain: 'llvm@20.1.7' }
- { os: macos-15-intel, toolchain: 'llvm@20.1.7' }
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-macos . full
- name: The exported surface is complete and contains nothing else
run: |
# Clause 9.3. The list and the checker come from the specification
# rather than from a copy kept here, so that the comparison has one
# source. --complete because this implementation claims every
# interface: a name it fails to export is a failure, not an interface
# it declines to provide.
rm -rf target && mcpp build
# This package's own objects, and not the ones the build tool emits
# beside them: one of those exists to initialise a standard library
# this package does not use, and it is not this package's to answer
# for.
objs="$(find target -path '*/obj/src/*' -name '*.o' ! -name '*.m.o' | tr '\n' ' ')"
test -n "$objs" || { echo "no objects were found" >&2; exit 1; }
bash .spec/tools/check-surface.sh --complete .spec/SURFACE.txt $objs
# The property version 0.3 exists for. The assertion is made against the
# objects rather than against the source, because a source can reach a C
# library through a macro.
- name: The objects reference nothing of a C library but the two named
run: |
rm -rf target && mcpp build --features standalone
objs="$(find target -path '*/obj/src/*' -name '*.o' ! -name '*.m.o')"
test -n "$objs" || { echo "no objects were found; the check would pass vacuously" >&2; exit 1; }
# The permitted set, and why each entry is in it.
#
# memcpy, memmove, memset, memcmp a compiler emits calls to these
# from ordinary loops. They compute rather than call, so none of
# them can re-enter this implementation.
# clock_gettime_nsec_np,
# pthread_create_from_mach_thread the two names no C library
# defines, which is why they are reachable from here at all.
# __libc_start_main, main, _main the hand-over, undefined here by
# construction.
# kal_* the interface itself.
# __stack_chk_* emitted by the toolchain around
# a frame it protects; supplied by the program, not called by this
# implementation.
permitted='^_?(memcpy|memmove|memset|memcmp|bzero|clock_gettime_nsec_np|pthread_create_from_mach_thread|pthread_create|pthread_join|__libc_start_main|main|kal_[a-z_]+|__stack_chk_guard|__stack_chk_fail|GCC_except_table.*|_ZN3okm.*|__Unwind_Resume)$'
# Reported with the object that references it. A symbol without the
# object it came from names a fault and not a place, and the first
# time this check fired the answer was in the object rather than in
# the symbol.
bad=0
for o in $objs; do
for s in $(nm -u "$o" | sed 's/^ *//' | grep -v ':$' | sort -u); do
[ -n "$s" ] || continue
printf '%s\n' "$s" | grep -qE "$permitted" || {
echo "$o references a symbol it must not: $s" >&2
bad=1
}
done
done
test "$bad" -eq 0
echo "the implementation reaches nothing of a C library but the two names that are named"
# 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 okm_probe(void) { puts("x"); }\n' > src/probe.cpp
rm -rf target && mcpp build --features standalone
objs="$(find target -path '*/obj/src/*' -name '*.o' ! -name '*.m.o')"
if ! nm -u $objs | sed 's/^ *//' | 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"