# BST-TIMEOUT: 300 . "$BST_LIB" # cglm 0.9.2 (meta-openembedded/meta-oe recipes-graphics, SRCREV c8781615 = tag # v0.9.2) -- OpenGL Mathematics for C. The port ships 179 headers under # /usr/include/cglm, libcglm.a, cglm.pc, and -- because that is what this ticket # asked for -- UPSTREAM'S OWN TEST SUITE, staged as /usr/libexec/cglm-tests. # # THE PASS CRITERION IS SECTION 4 AND EVERYTHING ELSE IS CONTEXT FOR IT. cglm # ships test/, meson builds it under -Dbuild_tests=true, and the recipe stages # the binary meson refuses to install. So this suite does not paraphrase the # library's correctness in a handful of hand-written assertions -- it runs the # 1053 checks upstream wrote and reads their verdict. Sections 1-3 exist so that # a red in section 4 is already half-attributed when a reader reaches it. # # THE SUITE COVERS THE ARCHIVE, not only the headers, and that is the reason the # archive is worth shipping at all. test/src/tests.c includes every test_*.h # TWICE -- once with GLM_PREFIX glm_ (the inline header implementations) and once # with glmc_ (the out-of-line symbols compiled into libcglm.a). 1053 is the total # of both passes, so a defect confined to the compiled objects is visible here # and a defect confined to the headers is too. # # WHICH SIMD PATH THIS IS, which the ticket named as the one thing to check # rather than assume. cglm/simd/intrin.h dispatches on the COMPILER's predefines: # __SSE*__/__AVX__ select x86, __ARM_NEON selects arm, and __wasm__ TOGETHER WITH # __wasm_simd128__ selects cglm's own WebAssembly backend. This toolchain # predefines none of them -- it does define __wasm_atomics__, __wasm_bulk_memory__, # __wasm_multivalue__, __wasm_mutable_globals__, __wasm_nontrapping_fptoint__, # __wasm_reference_types__ and __wasm_sign_ext__, and simd128 is not among them -- # so CGLM_SIMD is never defined and the build takes the SCALAR C path. # # THAT ANSWER IS STATED THREE TIMES BY THREE DIFFERENT AGENTS, on purpose: # # * cglm-oracle.txt (section 5) is the BUILD-TIME statement, taken by # preprocessing a probe at the recipe's own CFLAGS on the build host; # * cglm-arch's P-CGLM-ARCH (section 3) is the RUNTIME statement from this # image's own archive, on this target; # * cglm-arch's P-CGLM-ARCH-PRINT is UPSTREAM'S OWN WORD for it -- the string # glm_arch_print() emits -- and section 3 requires it to agree with the # other two. # # One of those could be wrong in isolation. Three agreeing, one of them written # by the library's author rather than by this port, is a measurement. # # THE TICKET'S OTHER WORRY -- that an x86 intrinsic might be reached and # "miscompile quietly" -- IS DISPOSED OF AT BUILD TIME AND CANNOT BE, and the # oracle's control is what establishes it: forcing __SSE2__ makes clang stop on # its own guard, `#error "This header is only meant to be used on x86 and x64 # architecture"`, in xmmintrin.h, mmintrin.h and emmintrin.h. It is a loud, # named compile failure three headers deep before an instruction is emitted, not # a silent wrong answer. Section 5 asserts that control ran. # # THE NATIVE COMPARISON, measured on the build host 2026-08-23 and the reason a # red here would be attributable at all. The same 1053 tests, same source, # compiled with gcc -O2 on x86-64: # # x86-64, SSE path (gcc's default): 1053 ran, 1053 passed, 0 failed, 0.11 s # x86-64, SCALAR path (-U__SSE*__): 1053 ran, 1053 passed, 0 failed, 0.12 s # # The second arm is the one that matters: it is the SAME code path this target # takes, on a reference architecture, and it is green. So a failure in section 4 # is a wasm32-hwjs finding, not a property of cglm's scalar fallback -- the # distinction that decides whether a red gets filed against brintOS or upstream. # # THE BOUND. 300 s declared against a measured target run (see the ==BST-SUITE # line this file emits). Native is 0.11 s and linux-in-the-browser#117 puts this # platform in the tens-of-times-slower band, so the expected cost is seconds and # the bound is headroom for a loaded host, not a fitted value. inc=/usr/include/cglm libdir=/usr/lib bindir=/usr/bin pcf=$libdir/pkgconfig/cglm.pc lib=$libdir/libcglm.a PT=/usr/libexec/cglm-tests # --------------------------------------------------------------------------- # 0. The canary, which exists to be thrown away. # # brintos/linux#96: a kernel console write landing immediately after # ==BST-BEGIN== DISPLACES the suite's first result line, so it never reaches the # host parser even though the case ran and the guest's own ==BST-SUMMARY== counts # it. Measured on this port's first target run (2026-08-23): the line lost was # `BST ok cglm/inc-dir`, displaced by # # [k] wasm32: the region holds pending signal(s) the kernel does not # (region 00000000_00010000 kernel 00000000_00000000) ... # # -- a DIFFERENT kernel message from the `hwjs-worker-stall` burst BRINTOS-1058 # and BRINTOS-1186 saw, which is why it is worth recording: the defect is not # specific to the stall, it is any kernel write at that moment. # # This case is that write's target. It asserts nothing anyone needs, so losing it # costs nothing, and inc-dir below keeps its meaning. It is deliberately FIRST # and deliberately trivial. bst_ok cglm/suite-canary # --------------------------------------------------------------------------- # 1. The payload. check cglm/inc-dir test -d "$inc" check cglm/call-dir test -d "$inc/call" check cglm/clipspace-dir test -d "$inc/clipspace" check cglm/handed-dir test -d "$inc/handed" check cglm/simd-dir test -d "$inc/simd" check cglm/struct-dir test -d "$inc/struct" # The umbrella headers a consumer writes #include against, plus the # three whose absence would break exactly the calls the probe and the suite make. for h in cglm.h common.h types.h version.h io.h call.h struct.h \ vec3.h vec4.h mat3.h mat4.h quat.h cam.h affine.h util.h; do check "cglm/header-$h" test -f "$inc/$h" done # simd/ SHIPS EVERY BACKEND'S HEADERS EVEN THOUGH THIS BUILD COMPILES NONE OF # THEM. That is upstream's install_subdir of include/cglm whole, and it is worth # pinning rather than trimming: the presence of simd/sse2 and simd/avx on a wasm32 # image is exactly the thing a reader could mistake for evidence that an x86 path # is live. It is not -- section 3 says which path the ARCHIVE took, and these are # unreferenced text on this arm. check cglm/simd-wasm-dir test -d "$inc/simd/wasm" check cglm/simd-sse2-dir test -d "$inc/simd/sse2" check cglm/simd-neon-dir test -d "$inc/simd/neon" check cglm/simd-avx-dir test -d "$inc/simd/avx" # Counted per directory, because these trees move independently upstream and a # single total would absorb a loss in one against a gain in another. Dated # snapshot, measured 2026-08-23 against cglm 0.9.2. check_eq cglm/file-count-total "179" "$(find "$inc" -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-root "47" "$(find "$inc" -maxdepth 1 -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-call "31" "$(find "$inc/call" -maxdepth 1 -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-clipspace "17" "$(find "$inc/clipspace" -maxdepth 1 -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-struct "32" "$(find "$inc/struct" -maxdepth 1 -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-simd "4" "$(find "$inc/simd" -maxdepth 1 -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-simd-wasm "5" "$(find "$inc/simd/wasm" -maxdepth 1 -type f 2>/dev/null | grep -c .)" check_eq cglm/file-count-simd-sse2 "5" "$(find "$inc/simd/sse2" -maxdepth 1 -type f 2>/dev/null | grep -c .)" # The archive, and the shared object that must NOT be here. -Ddefault_library=static # is the distro's standing rule (brintos.conf: --disable-shared everywhere, # b_asneeded/b_lundef off for meson) and for cglm it is also the only way the # recipe links at all -- wasmld refuses the -shared side-module link outright. check cglm/static-archive test -f "$lib" check_eq cglm/no-shared-object "0" \ "$(find "$libdir" -maxdepth 1 -name 'libcglm.so*' 2>/dev/null | grep -c .)" # ${PN} is never produced -- default_library=static means library() emits # libcglm.a and there is no libcglm.so.* for a main package to hold -- so # nothing named plain `cglm` should be installed outside -dev/-staticdev/-tests. check_eq cglm/no-cglm-binary "0" \ "$(find "$bindir" -maxdepth 1 -name 'cglm*' 2>/dev/null | grep -c .)" check cglm/tests-dir test -d "$PT" check cglm/tests-binary test -f "$PT/cglm-tests" check cglm/tests-exec test -x "$PT/cglm-tests" check cglm/arch-binary test -x "$PT/cglm-arch" check cglm/oracle-report test -f "$PT/cglm-oracle.txt" # --------------------------------------------------------------------------- # 2. The integration surface. check cglm/pc-file test -f "$pcf" pc=$(cat "$pcf" 2>/dev/null) case "$pc" in *"Version: 0.9.2"*) pv=ok ;; *) pv=absent ;; esac check_eq cglm/pc-version "ok" "$pv" # -DCGLM_STATIC in the .pc is the CONSUMER-VISIBLE proof that the archive was # configured static. On this arm it is a marker rather than load-bearing # arithmetic -- common.h only consults CGLM_STATIC to pick MSVC's dllimport vs # dllexport -- but a .pc that lost it would mean -Ddefault_library=static never # reached cglm_args, and that IS load-bearing: it is what makes the link work. case "$pc" in *"-DCGLM_STATIC"*) ps=ok ;; *) ps=absent ;; esac check_eq cglm/pc-static-flag "ok" "$ps" case "$pc" in *"-DCGLM_HAVE_BUILTIN_ASSUME_ALIGNED=1"*) pa=ok ;; *) pa=absent ;; esac check_eq cglm/pc-assume-aligned "ok" "$pa" case "$pc" in *'Libs: -L${libdir} -lcglm -lm'*) pl=ok ;; *) pl=other ;; esac check_eq cglm/pc-libs-template "ok" "$pl" case "$pc" in *'Cflags: -I${includedir}'*) pi=ok ;; *) pi=other ;; esac check_eq cglm/pc-cflags-template "ok" "$pi" # pkgconf emits a TRAILING SPACE after the last flag of --cflags and --libs # (measured on the build host, and it is a separator artefact rather than a # version detail worth pinning), so every query below goes through this: word # splitting and re-joining collapses runs of whitespace and strips both ends. # Written once, here, because the trailing space is invisible in a transcript # and a suite that hard-coded it would go red the day pkgconf stopped emitting # it -- a failure that reads as a broken .pc and is not one. _cglm_ws() { set -- $1; printf '%s' "$*"; } if command -v pkg-config >/dev/null 2>&1; then bst_ok cglm/pkgconf-present check cglm/pkgconf-exists pkg-config --exists cglm check_eq cglm/pkgconf-modversion "0.9.2" "$(pkg-config --modversion cglm 2>&1)" check_eq cglm/pkgconf-libdir "/usr/lib" "$(pkg-config --variable=libdir cglm 2>&1)" check_eq cglm/pkgconf-includedir "/usr/include" "$(pkg-config --variable=includedir cglm 2>&1)" # -I/usr/include is dropped by pkgconf because it is on its compiled-in # PKG_CONFIG_SYSTEM_INCLUDE_PATH -- the compiler already searches it, so # emitting it would reorder the search path. The two -D flags are NOT # filtered, which is what makes this the assertion that a consumer really # gets the configuration the archive was built under. A reader running the # command by hand and seeing no -I is looking at correct behaviour; the # pkgconf-includedir case above is where the include path is asserted. check_eq cglm/pkgconf-cflags \ "-DCGLM_STATIC -DCGLM_HAVE_BUILTIN_ASSUME_ALIGNED=1" \ "$(_cglm_ws "$(pkg-config --cflags cglm 2>&1)")" check_eq cglm/pkgconf-libs "-lcglm -lm" \ "$(_cglm_ws "$(pkg-config --libs cglm 2>&1)")" else bst_skip cglm/pkgconf-present "pkgconf not installed on this image" fi # THE VERSION MACROS LIVE IN A HEADER NOTHING INCLUDES. cglm/version.h defines # CGLM_VERSION_MAJOR/MINOR/PATCH and is included by no other header in the tree # -- not even cglm.h, which pulls in 34 others. A consumer that wants the version # must name it. Pinned because it is a real integration surprise (it cost this # port one build) and because a future upstream that wires it into cglm.h would # otherwise change a consumer's macro state silently. vh=$(cat "$inc/version.h" 2>/dev/null) case "$vh" in *"#define CGLM_VERSION_MAJOR 0"*) vm=ok ;; *) vm=absent ;; esac case "$vh" in *"#define CGLM_VERSION_MINOR 9"*) vn=ok ;; *) vn=absent ;; esac case "$vh" in *"#define CGLM_VERSION_PATCH 2"*) vp=ok ;; *) vp=absent ;; esac check_eq cglm/version-header "ok ok ok" "$vm $vn $vp" check_eq cglm/version-header-unreferenced "0" \ "$(grep -l 'include.*version\.h' "$inc"/*.h 2>/dev/null | grep -c .)" # --------------------------------------------------------------------------- # 3. The arch probe -- THE SIMD ANSWER, made on target by this image's archive. if [ ! -x "$PT/cglm-arch" ]; then bst_skip cglm/arch-probe-present "cglm-arch not installed on this image" else bst_ok cglm/arch-probe-present aout=$("$PT/cglm-arch" 2>&1); arc=$? P_ARCH=; P_SIMD=; P_WASM=; P_X86=; P_ARM=; P_M128=; P_XMAC=; P_UNAL= P_PRINT=; P_VER=; P_PTR=; P_FLT=; P_V4B=; P_M4B=; P_QB= P_MUL=; P_MULV=; P_N3=; P_QN=; P_RES= oIFS=$IFS; IFS=' ' for line in $aout; do tag=${line%% *}; val=${line#* } case "$tag" in P-CGLM-ARCH) P_ARCH=$val ;; P-CGLM-SIMD) P_SIMD=$val ;; P-CGLM-SIMD-WASM) P_WASM=$val ;; P-CGLM-SIMD-X86) P_X86=$val ;; P-CGLM-SIMD-ARM) P_ARM=$val ;; P-WASM-SIMD128-MACRO) P_M128=$val ;; P-X86-MACRO) P_XMAC=$val ;; P-CGLM-ALL-UNALIGNED) P_UNAL=$val ;; P-CGLM-ARCH-PRINT) P_PRINT=$val ;; P-CGLM-VERSION) P_VER=$val ;; P-PTR-BITS) P_PTR=$val ;; P-FLOAT-BITS) P_FLT=$val ;; P-VEC4-BYTES) P_V4B=$val ;; P-MAT4-BYTES) P_M4B=$val ;; P-VERSOR-BYTES) P_QB=$val ;; P-MAT4-MUL) P_MUL=$val ;; P-MAT4-MULV) P_MULV=$val ;; P-NORMALIZE3) P_N3=$val ;; P-QUAT-NORMALIZE) P_QN=$val ;; P-RESULT) P_RES=$val ;; esac done IFS=$oIFS # The arch answer on the console, for the same reason: the assertions below # turn it into pass/fail, and the transcript should carry the words. echo "cglm-arch selected=$P_ARCH upstream-says='$P_PRINT' simd=$P_SIMD wasm=$P_WASM x86=$P_X86 arm=$P_ARM ptr-bits=$P_PTR" check_eq cglm/arch-probe-exit "0" "$arc" check_eq cglm/arch-probe-result "OK" "$P_RES" # THE ANSWER. check_eq cglm/arch-selected "scalar" "$P_ARCH" check_eq cglm/arch-simd-off "0" "$P_SIMD" check_eq cglm/arch-no-wasm-simd "0" "$P_WASM" check_eq cglm/arch-no-x86 "0" "$P_X86" check_eq cglm/arch-no-arm "0" "$P_ARM" # The two compiler predefines the whole dispatch turns on, read directly. check_eq cglm/macro-no-wasm-simd128 "0" "$P_M128" check_eq cglm/macro-no-x86 "0" "$P_XMAC" check_eq cglm/all-unaligned-off "0" "$P_UNAL" # UPSTREAM'S OWN WORD, and the case that makes the four above a measurement # rather than a restatement of this port's own #ifdef chain. glm_arch_print() # prints "uncommon" for the no-SIMD arm -- upstream's term, not ours. check_eq cglm/arch-print-agrees "arch: uncommon" "$P_PRINT" check_eq cglm/probe-version "0.9.2" "$P_VER" check_eq cglm/probe-ptr-bits "32" "$P_PTR" check_eq cglm/probe-float-bits "32" "$P_FLT" # Layout: vec4 and versor are four tightly packed floats, mat4 sixteen. A # padded type would mean an aligned-gentype path was in play, which is what # the arch cases above rule out -- asserted here too because a size is what a # consumer's own struct layout depends on. check_eq cglm/probe-vec4-bytes "16" "$P_V4B" check_eq cglm/probe-mat4-bytes "64" "$P_M4B" check_eq cglm/probe-versor-bytes "16" "$P_QB" # Four values from the ARCHIVE's out-of-line entry points, byte-compared # against the same source built with gcc on x86-64's scalar path (measured # 2026-08-23). Integer and exactly-representable inputs only, so every one is # exact under IEEE-754 and a divergence is arithmetic rather than rounding. check_eq cglm/mat4-mul "1 3 5 -6" "$P_MUL" check_eq cglm/mat4-mulv "7 6 12 1" "$P_MULV" check_eq cglm/quat-normalize "0.5 0.5 0.5 0.5" "$P_QN" # (3,4,12) has length exactly 13, so this is a correctly rounded division of # exact integers and must match the reference digit for digit. check_eq cglm/normalize3 "0.230769247 0.307692319 0.923076987" "$P_N3" fi # --------------------------------------------------------------------------- # 4. THE PASS CRITERION -- upstream's own suite, run on target. if [ ! -x "$PT/cglm-tests" ]; then bst_notok cglm/upstream-suite-present "no executable $PT/cglm-tests -- the ticket's pass criterion cannot be evaluated" else bst_ok cglm/upstream-suite-present # The runner writes EVERYTHING to stderr (test/runner.c uses fprintf(stderr, # ...) throughout) and returns the number of failures as its exit status. tout=$("$PT/cglm-tests" 2>&1); trc=$? check_eq cglm/upstream-suite-rc "0" "$trc" # The runner's own summary line, parsed rather than grepped, so a truncated # or reordered run cannot pass by containing the right words somewhere. summary=$(printf '%s\n' "$tout" | grep 'tests ran,' | head -1) ran=$(printf '%s\n' "$summary" | sed -n 's/^\([0-9][0-9]*\) tests ran.*/\1/p') passed=$(printf '%s\n' "$summary" | sed -n 's/.*, \([0-9][0-9]*\) passed.*/\1/p') failed=$(printf '%s\n' "$summary" | sed -n 's/.*, \([0-9][0-9]*\) failed.*/\1/p') # THE CRITERION IN ITS OWN WORDS, on every run and not only on a red. The # cases below reduce this line to booleans, and a reviewer reading a # transcript should not have to take the booleans' word for what the runner # said. It is outside the BST protocol, so the report parsers ignore it. echo "cglm-upstream $summary (rc=$trc)" echo "cglm-upstream x86-64-ref-sse 1053 tests ran, 1053 passed, 0 failed (0.11 s)" echo "cglm-upstream x86-64-ref-scalar 1053 tests ran, 1053 passed, 0 failed (0.12 s)" # A FLOOR, not an equality: upstream adds tests between releases and a bump # that ADDS coverage must not read as a regression. A drop below it means the # suite stopped running cases, which is the failure this catches. if [ -n "$ran" ] && [ "$ran" -ge 1053 ]; then bst_ok cglm/upstream-suite-count else bst_notok cglm/upstream-suite-count "ran='$ran', expected not less than 1053 (x86-64 reference ran 1053 on both the SSE and the scalar path)" fi # These two ARE equalities, and between them they say the run was complete: # every case that ran passed, and none failed. check_eq cglm/upstream-suite-failed "0" "$failed" check_eq cglm/upstream-suite-passed "$ran" "$passed" # The runner prints this line only when failed == 0, so it is an independent # statement of the same verdict from a different branch of runner.c. case "$tout" in *"All tests passed"*) allok=ok ;; *) allok=absent ;; esac check_eq cglm/upstream-suite-all-passed "ok" "$allok" # On a red, put the failing test names on the console. The runner prints one # line per failure carrying the test name and any message, and without this a # reader gets a count and has to rebuild and reboot to learn WHICH of 1053 # cases went. Costs nothing on a green run. if [ "$trc" != 0 ] || [ "$failed" != "0" ]; then echo "cglm-failures summary: $summary (rc=$trc)" printf '%s\n' "$tout" | grep -i 'assert fail' | head -20 | \ while read -r l; do echo "cglm-failures $l"; done printf '%s\n' "$tout" | sed -n 's/.*\(𐄂\)/FAILED/p' | head -20 | \ while read -r l; do echo "cglm-failures-case $l"; done echo "cglm-failures x86-64-ref-sse 1053 ran, 1053 passed, 0 failed" echo "cglm-failures x86-64-ref-scalar 1053 ran, 1053 passed, 0 failed" fi fi # --------------------------------------------------------------------------- # 5. The build-time oracle, shipped beside the binaries it vouches for. # # Its nine gates ran on the build host at the recipe's own CFLAGS; this section # only asserts that the report arrived intact and says what it said. The two # CONTROL gates are named individually because they are what make the other # seven mean anything: control-wasm-simd forces -msimd128 and requires the arch # token to CHANGE (so the scalar answer is a decision, not an inert probe), and # control-x86-refused forces __SSE2__ and requires a HARD COMPILE ERROR (so the # ticket's quiet-miscompile worry is ruled out rather than assumed away). orep=$PT/cglm-oracle.txt if [ ! -f "$orep" ]; then bst_notok cglm/oracle-present "no $orep" else bst_ok cglm/oracle-present o=$(cat "$orep" 2>/dev/null) case "$o" in *" END"*) oe=ok ;; *) oe=truncated ;; esac check_eq cglm/oracle-complete "ok" "$oe" check_eq cglm/oracle-gates-passed "9" "$(printf '%s\n' "$o" | grep -c '^GATE .* PASS ')" check_eq cglm/oracle-gates-failed "0" "$(printf '%s\n' "$o" | grep -c '^GATE .* FAIL ')" check_eq cglm/oracle-arch "scalar" "$(printf '%s\n' "$o" | sed -n 's/^ARCH //p')" for g in arch-selected control-wasm-simd control-x86-refused no-simd-macros \ tests-binary static-only pc-static-marker consumer-link control-undefined; do check_eq "cglm/oracle-gate-$g" "1" \ "$(printf '%s\n' "$o" | grep -c "^GATE $g PASS ")" done fi