diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8426e69..6e41895 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -694,6 +694,10 @@ jobs: # # openkal = "0.5.2" a released version. The question is # whether it is this one. + # openkal = "^0.24.0" a compatible range (a caret: the + # same 0.y, or the same major above 0, + # and not older). The question is + # whether this version is in it. # openkal = { git = …, branch = … } # a development line. The version is # not stated and cannot be; what makes @@ -705,7 +709,21 @@ jobs: # empty string --- which named neither the cause nor the symptom. here="$(sed -n 's/^version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' mcpp.toml | head -1)" there="$(sed -n 's/^openkal[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' .impl/mcpp.toml | head -1)" - if [ -n "$there" ]; then + in_range() { # in_range VERSION ^FLOOR + local v="$1" floor="${2#^}" + IFS=. read -r vmaj vmin _ <<<"$v" + IFS=. read -r fmaj fmin _ <<<"$floor" + [ "$vmaj" = "$fmaj" ] || return 1 + [ "$fmaj" != 0 ] || [ "$vmin" = "$fmin" ] || return 1 + [ "$(printf '%s\n%s\n' "$floor" "$v" | sort -V | head -1)" = "$floor" ] + } + if [ -n "$there" ] && [ "${there#^}" != "$there" ]; then + if ! in_range "$here" "$there"; then + echo "::error::this is openkal $here and ${{ matrix.implementation }} is written against openkal $there, a range without it. They are not in step." >&2 + exit 1 + fi + echo "openkal $here is in ${{ matrix.implementation }}'s range $there" + elif [ -n "$there" ]; then if [ "$here" != "$there" ]; then echo "::error::this is openkal $here and ${{ matrix.implementation }} is written against openkal $there. Nothing is wrong with either; they are not in step. Re-run after the implementation's branch has the matching version." >&2 exit 1 diff --git a/SPEC.md b/SPEC.md index 4dfe153..548bcb9 100644 --- a/SPEC.md +++ b/SPEC.md @@ -2152,6 +2152,7 @@ the operations a loader needs and a program could not otherwise reach | imports | only names this specification declares, and names other images export; a name of a C library or of an environment is refused. A weak import is optional: it is bound when the implementation or an image the image needs provides it, and is zero otherwise | | entry | an executable image's ELF entry is a function of no parameters returning `int`, in the image's convention; its value is the image's status. An image that another loads has no entry | | calling convention | the architecture's, fixed for every environment: the System V convention on x86-64, the procedure call standard on AArch64; an implementation whose environment uses another presents entries in this one to the image (12.3) | +| floating-point state | the convention's at the entry and in each context: on x86-64 the x87 control word `0x037F` (extended precision, every exception masked) and MXCSR `0x1F80`, on AArch64 FPCR zero; an image's C library computes in that state (a `long double` of x86-64 is the x87's extended format) | | platform register | an AArch64 image does not use `x18`, which two environments reserve | | stack | a frame larger than a page is touched page by page, in order: one environment commits a context's stack as its guard page is touched, and a frame that steps over the guard ends the program | | thread-local storage | through the emulated form, in which a variable is found by a function the image itself supplies; an image does not address the thread pointer, which one environment does not let a program set and another does not let it change | @@ -2206,7 +2207,12 @@ Where an environment's own convention differs from the image's --- on x86-64, one environment passes arguments in other registers --- the loader presents each entry in the image's convention, and a function the image passes to the implementation (`kal_task_start`'s entry, `kal_space_start`'s) is entered in the -image's convention. The presentation is mechanical and is generated from +image's convention. The convention includes the floating-point state (12.2): the +loader establishes it at the entry, for the initialisers and finalisers, and in +each context the image starts, and a call that a program of the environment makes +into an image's function is made in it, the caller's own restored after it; one +environment begins a thread with the x87 at double precision. The presentation is +mechanical and is generated from `SURFACE.txt` and the declarations, so that it cannot omit a name. It is the loader's and not the implementation's: an implementation is written in its environment's convention, as every program of that environment is, and a