. "$BST_LIB" # libconfig is a structured-configuration-file library: a flex scanner and a # bison parser over a typed setting tree (group / array / list plus six scalar # types), a writer that renders the tree back to the same syntax, and an # @include directive the lexer resolves mid-parse. # # The distro is static-only and libconfig has NO CLI of its own, so the whole # installed payload is one header, one pkg-config file, the # find_package(libconfig) cmake file (-dev) and the archive libconfig.a # (-staticdev). # # --------------------------------------------------------------------------- # WHY THIS SUITE RUNS A PROBE INSTEAD OF STOPPING AT PAYLOAD SHAPE # # BRINTOS-217: oniguruma COMPILED and PACKAGED perfectly on this arm and then # returned silently wrong match offsets to every caller, so a payload-only suite # would have gone green on the exact defect the port existed to find. libconfig # is the same shape of risk and more of it -- lib/scanner.c and lib/grammar.c are # GENERATED flex/bison output, a loop-carried cursor walked by pointer # arithmetic, which is the class hwjs-cc#24 broke for onig. # # So data/libconfig-probe is cross-linked with wasmcc-glibc against THE VERY # ARCHIVE THAT SHIPS (/usr/lib/libconfig.a), staged to $TMPDIR and run here. Its # source is src/libconfig_probe.c. The cross-link reported # `refused=0 skipped=0 ... invalid_functions=0 module_broken=0`, and the pass # coroutinized libconfig_yyparse, libconfig_yylex, libconfig_yy_scan_string, # __config_read, __config_write_value, config_read_file, config_write_file, # config_setting_add, every config_setting_set_*_elem mutator and # config_default_include_func -- so the parser, the scanner, the writer, the # mutators and the include resolver are ALL genuinely rewritten on this arm, and # the stdio-*, include-* and deep-* groups below are what measure that. # # EVERY EXPECTED VALUE IS THE VALUE A NATIVE x86_64 BUILD OF THE IDENTICAL # RELEASE PRODUCES. The probe compares each value internally and prints its own # verdict, so the cases below assert the verdict while the console dump carries # the value for diagnosis. The native control scored 130/130, and it corrected # five assertions of mine before it did -- the typed config_setting_lookup_* # calls take a direct member name and NOT a dotted path (two of the five), and # @include takes no trailing semicolon. Both are now asserted in both directions # rather than quietly worked around. # # --------------------------------------------------------------------------- # WHY BUILTIN MATCHING INSTEAD OF check_out # # The probe runs ONCE and the payload files are read ONCE into shell variables; # every assertion is a `case` glob against them, so there is no fork per case. # The cjson suite next door was killed by the runner's per-suite bound # (BST_SUITE_TIMEOUT) at 156 cases written as check_out+cat: on the wasm32-hwjs # runtime the forking IS the cost, not the work. # --------------------------------------------------------------------------- incd=/usr/include lib=/usr/lib/libconfig.a pc=/usr/lib/pkgconfig/libconfig.pc cm=/usr/lib/cmake/libconfig nl=' ' # hasfile -- ok iff is a non-empty regular file. # has -- ok iff contains the literal . # hasline -- ok iff carries as a WHOLE line. # Substring matching would let config_setting_add # satisfy a lookup for config_setting, and # config_read_file one for config_read. hasfile() { if [ -s "$2" ]; then bst_ok "$1"; else bst_notok "$1" "absent or empty: $2"; fi; } has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "not found: $2" ;; esac; } hasline() { case "$nl$3$nl" in *"$nl$2$nl"*) bst_ok "$1" ;; *) bst_notok "$1" "not in archive: $2" ;; esac; } # --- the shipped payload ----------------------------------------------------- hasfile libconfig/header "$incd/libconfig.h" hasfile libconfig/archive "$lib" hasfile libconfig/pkgconfig "$pc" hasfile libconfig/cmake-config "$cm/libconfigConfig.cmake" pctext=$(cat "$pc" 2>/dev/null) has libconfig/pc-name "Name: libconfig" "$pctext" has libconfig/pc-version "Version: 1.7.3" "$pctext" has libconfig/pc-libs "-lconfig" "$pctext" has libconfig/pc-cflags "Cflags: -I\${includedir}" "$pctext" # --- the C++ half, which this arm cannot build yet --------------------------- # libconfig ships a SECOND library, libconfig++, whose whole error-reporting # contract is C++ exceptions: seven exception classes deriving from # std::exception, 20 throw statements and two try/catch blocks in # lib/libconfigcpp.c++. The C++ driver this layer stages is the EXCEPTIONS-OFF # libc++ arm (scripts/build-libcxx.sh) and bakes -fno-exceptions into every # compile, because the exceptions-on arm is blocked upstream by # brintos/hwjs-cc#10 -- so clang rejects the file outright, once per throw. The # recipe therefore configures --disable-cxx. # # These are SKIPs rather than silent omissions: they name the blocking issue, and # they flip to real cases the moment #10 lands and --disable-cxx comes off. bst_skip libconfig/cxx-header "libconfig.h++ not shipped: --disable-cxx, C++ exceptions blocked by brintos/hwjs-cc#10" bst_skip libconfig/cxx-archive "libconfig++.a not shipped: --disable-cxx, C++ exceptions blocked by brintos/hwjs-cc#10" bst_skip libconfig/cxx-runtime "libconfig++ API unexercised: needs the exceptions-on libc++ arm (brintos/hwjs-cc#10)" # The C header must NOT have dragged its C++ twin in behind --disable-cxx. if [ -e "$incd/libconfig.h++" ] || [ -e /usr/lib/libconfig++.a ]; then bst_notok libconfig/cxx-absent-as-configured "--disable-cxx was set, yet a C++ artifact shipped" else bst_ok libconfig/cxx-absent-as-configured fi # --- symbol completeness, tracked from the INSTALLED header ------------------ # Every function the installed header declares must be present in the installed # archive, so a partial compile, a visibility mistake or a header/library skew # all fail this. The list is DERIVED from the header rather than written here, so # it survives a version bump; two pipelines are the only forks. # # The `grep -v '^#'` is load-bearing, not tidying: sed will not close a # /start/,/;/ range on the start line itself, so a one-line declaration such as # `extern LIBCONFIG_API void config_set_hook(config_t *, void *);` keeps the # range open to the NEXT semicolon and drags the intervening # `#define config_get_hook(C) ((C)->hook)` in with it. Most of libconfig's # accessors (config_setting_type, config_root_setting, config_error_text, ...) # are macros of exactly that kind and are correctly outside this derivation. # # config_set_default_format is excluded BY CONSTRUCTION, and it is the one name # in this header that needs explaining. It is declared as a function at # libconfig.h:134 AND #defined as a macro at libconfig.h:324; the macro wins for # every caller, so no archive symbol is ever emitted or needed. That is upstream # libconfig's own inconsistency, identical on a native x86_64 build of the same # release (checked -- the native archive does not carry it either, and a native # caller links because the macro expands), so it is not a platform gap and not # something this port introduced. arcsyms=$(grep -ao 'config[a-z0-9_]*' "$lib" 2>/dev/null | sort -u) hdrsyms=$(sed -n '/^extern LIBCONFIG_API/,/;/p' "$incd/libconfig.h" 2>/dev/null \ | grep -v '^[[:space:]]*#' \ | grep -oE '\bconfig_[a-z0-9_]*\(' | sed 's/(//' | sort -u) nsym=0 nmiss=0 missing="" for f in $hdrsyms; do case "$f" in config_set_default_format) continue ;; esac nsym=$((nsym + 1)) case "$nl$arcsyms$nl" in *"$nl$f$nl"*) ;; *) nmiss=$((nmiss + 1)); missing="$missing $f" ;; esac done if [ "$nmiss" -eq 0 ]; then bst_ok libconfig/symbols-complete else bst_notok libconfig/symbols-complete "$nmiss missing:$missing" fi check_eq libconfig/symbols-count 65 "$nsym" # A spot-check that the derivation above is really reading the archive and not an # empty string that would make the loop vacuously green -- one from each of the # five areas the probe drives. hasline libconfig/sym-read-string config_read_string "$arcsyms" hasline libconfig/sym-write-file config_write_file "$arcsyms" hasline libconfig/sym-lookup-int64 config_lookup_int64 "$arcsyms" hasline libconfig/sym-setting-add config_setting_add "$arcsyms" hasline libconfig/sym-include-dir config_set_include_dir "$arcsyms" # The generated flex/bison half must be in the archive too -- it is the part of # libconfig most likely to be lost to a build that "succeeded", since it is the # only code the tarball ships pre-generated. It needs its OWN scan rather than # reusing $arcsyms: that pattern starts at `config`, so it reduces # `libconfig_yyparse` to `config_yyparse` and a lookup for the real name can # never match (which is exactly what it did on the first on-target run). yysyms=$(grep -ao 'libconfig_yy[a-z0-9_]*' "$lib" 2>/dev/null | sort -u) hasline libconfig/sym-yyparse libconfig_yyparse "$yysyms" hasline libconfig/sym-yylex libconfig_yylex "$yysyms" hasline libconfig/sym-yy-scan-string libconfig_yy_scan_string "$yysyms" # --- the library RUNNING, via the cross-linked probe ------------------------- # The probe writes files, so it gets a private scratch directory: the deployed # rootfs is read-only at browser runtime and $TMPDIR is the one writable place. probe=${TMPDIR:-/tmp}/bst-libconfig-probe.$$ scratch=${TMPDIR:-/tmp}/bst-libconfig-scratch.$$ if cp "$BST_DATA/libconfig-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null \ && mkdir -p "$scratch" 2>/dev/null; then out=$("$probe" "$scratch" 2>&1) # parse and lookup: every scalar type the grammar has, plus the two ways a # lookup can legitimately fail has libconfig/run-parse-string "LC-parse-string OK" "$out" has libconfig/run-lookup-string "LC-lookup-string OK" "$out" has libconfig/run-lookup-int "LC-lookup-int OK" "$out" has libconfig/run-lookup-int-neg "LC-lookup-int-neg OK" "$out" has libconfig/run-lookup-int64 "LC-lookup-int64 OK" "$out" has libconfig/run-lookup-int64-neg "LC-lookup-int64-neg OK" "$out" has libconfig/run-lookup-float "LC-lookup-float OK" "$out" has libconfig/run-lookup-float-sci "LC-lookup-float-sci OK" "$out" has libconfig/run-lookup-bool-true "LC-lookup-bool-true OK" "$out" has libconfig/run-lookup-bool-false "LC-lookup-bool-false OK" "$out" has libconfig/run-lookup-hex "LC-lookup-hex OK" "$out" has libconfig/run-lookup-absent "LC-lookup-absent OK" "$out" has libconfig/run-lookup-null-setting "LC-lookup-null-setting OK" "$out" has libconfig/run-lookup-type-mismatch "LC-lookup-type-mismatch OK" "$out" # the scanner's escape table, rendered byte by byte, and the grammar's # adjacent-literal concatenation has libconfig/run-escape-decode "LC-escape-decode OK" "$out" has libconfig/run-escape-len "LC-escape-len OK" "$out" has libconfig/run-string-concat "LC-string-concat OK" "$out" # the type system and the tree's shape has libconfig/run-type-group "LC-type-group OK" "$out" has libconfig/run-is-group "LC-is-group OK" "$out" has libconfig/run-group-name "LC-group-name OK" "$out" has libconfig/run-type-array "LC-type-array OK" "$out" has libconfig/run-array-len "LC-array-len OK" "$out" has libconfig/run-is-array "LC-is-array OK" "$out" has libconfig/run-type-list "LC-type-list OK" "$out" has libconfig/run-list-len "LC-list-len OK" "$out" has libconfig/run-is-list "LC-is-list OK" "$out" has libconfig/run-type-int64 "LC-type-int64 OK" "$out" has libconfig/run-type-int "LC-type-int OK" "$out" has libconfig/run-type-float "LC-type-float OK" "$out" has libconfig/run-type-bool "LC-type-bool OK" "$out" has libconfig/run-type-str "LC-type-str OK" "$out" has libconfig/run-scalar-not-agg "LC-scalar-not-agg OK" "$out" has libconfig/run-empty-array "LC-empty-array OK" "$out" has libconfig/run-empty-list "LC-empty-list OK" "$out" has libconfig/run-root-is-root "LC-root-is-root OK" "$out" has libconfig/run-parent-chain "LC-parent-chain OK" "$out" has libconfig/run-root-parent-null "LC-root-parent-null OK" "$out" # element and member access -- the offset arithmetic BRINTOS-217 got wrong # for onig, asserted by value and by order rather than by length alone has libconfig/run-array-elem-sum "LC-array-elem-sum OK" "$out" has libconfig/run-array-order "LC-array-order OK" "$out" has libconfig/run-get-elem "LC-get-elem OK" "$out" has libconfig/run-elem-index "LC-elem-index OK" "$out" has libconfig/run-get-elem-oob "LC-get-elem-oob OK" "$out" has libconfig/run-list-elem0-int "LC-list-elem0-int OK" "$out" has libconfig/run-list-elem1-str "LC-list-elem1-str OK" "$out" has libconfig/run-list-elem2-float "LC-list-elem2-float OK" "$out" has libconfig/run-list-elem3-bool "LC-list-elem3-bool OK" "$out" has libconfig/run-list-elem4-nested "LC-list-elem4-nested OK" "$out" has libconfig/run-get-member "LC-get-member OK" "$out" has libconfig/run-get-member-absent "LC-get-member-absent OK" "$out" # the typed-vs-pointer lookup asymmetry: config_setting_lookup_() # takes a DIRECT MEMBER NAME while config_setting_lookup() walks a dotted # path has libconfig/run-setting-lookup-int "LC-setting-lookup-int OK" "$out" has libconfig/run-setting-lookup-int64 "LC-setting-lookup-int64 OK" "$out" has libconfig/run-setting-lookup-float "LC-setting-lookup-float OK" "$out" has libconfig/run-setting-lookup-bool "LC-setting-lookup-bool OK" "$out" has libconfig/run-setting-lookup-string "LC-setting-lookup-string OK" "$out" has libconfig/run-setting-lookup-absent "LC-setting-lookup-absent OK" "$out" has libconfig/run-setting-lookup-typed-is-not-a-path "LC-setting-lookup-typed-is-not-a-path OK" "$out" has libconfig/run-setting-lookup-ptr-is-a-path "LC-setting-lookup-ptr-is-a-path OK" "$out" has libconfig/run-setting-lookup-ptr-index "LC-setting-lookup-ptr-index OK" "$out" # integer format memory and the two global render settings has libconfig/run-format-hex-kept "LC-format-hex-kept OK" "$out" has libconfig/run-format-default "LC-format-default OK" "$out" has libconfig/run-set-format-hex "LC-set-format-hex OK" "$out" has libconfig/run-set-format-back "LC-set-format-back OK" "$out" has libconfig/run-set-format-refused "LC-set-format-refused OK" "$out" has libconfig/run-float-precision-default "LC-float-precision-default OK" "$out" has libconfig/run-float-precision-set "LC-float-precision-set OK" "$out" has libconfig/run-tab-width-default "LC-tab-width-default OK" "$out" has libconfig/run-tab-width-set "LC-tab-width-set OK" "$out" # the option mask, autoconvert asserted by its effect on a GET rather than # by flag state has libconfig/run-opt-semicolon-default "LC-opt-semicolon-default OK" "$out" has libconfig/run-opt-autoconvert-default "LC-opt-autoconvert-default OK" "$out" has libconfig/run-opt-autoconvert-set "LC-opt-autoconvert-set OK" "$out" has libconfig/run-autoconvert-float-as-int "LC-autoconvert-float-as-int OK" "$out" has libconfig/run-autoconvert-int-as-float "LC-autoconvert-int-as-float OK" "$out" has libconfig/run-opt-autoconvert-cleared "LC-opt-autoconvert-cleared OK" "$out" has libconfig/run-opt-mask-roundtrip "LC-opt-mask-roundtrip OK" "$out" # building a document programmatically, and the invariants a builder must # enforce (no duplicate member, arrays type-uniform, lists not) has libconfig/run-add-group "LC-add-group OK" "$out" has libconfig/run-add-string "LC-add-string OK" "$out" has libconfig/run-add-int "LC-add-int OK" "$out" has libconfig/run-add-int64 "LC-add-int64 OK" "$out" has libconfig/run-add-float "LC-add-float OK" "$out" has libconfig/run-add-bool "LC-add-bool OK" "$out" has libconfig/run-add-duplicate-refused "LC-add-duplicate-refused OK" "$out" has libconfig/run-array-append "LC-array-append OK" "$out" has libconfig/run-array-set-elem "LC-array-set-elem OK" "$out" has libconfig/run-array-type-uniform "LC-array-type-uniform OK" "$out" has libconfig/run-list-heterogeneous "LC-list-heterogeneous OK" "$out" has libconfig/run-remove-elem "LC-remove-elem OK" "$out" has libconfig/run-remove-elem-oob "LC-remove-elem-oob OK" "$out" has libconfig/run-remove-member "LC-remove-member OK" "$out" has libconfig/run-remove-absent "LC-remove-absent OK" "$out" has libconfig/run-clear "LC-clear OK" "$out" has libconfig/run-destroy-after-clear "LC-destroy-after-clear OK" "$out" # errors reported BY TYPE AND LINE, not merely as a rejection -- a broken # parser also rejects things has libconfig/run-parse-error-rc "LC-parse-error-rc OK" "$out" has libconfig/run-parse-error-type "LC-parse-error-type OK" "$out" has libconfig/run-parse-error-line "LC-parse-error-line OK" "$out" has libconfig/run-parse-error-text "LC-parse-error-text OK" "$out" has libconfig/run-unterminated-group "LC-unterminated-group OK" "$out" has libconfig/run-bad-array-mix "LC-bad-array-mix OK" "$out" has libconfig/run-duplicate-key "LC-duplicate-key OK" "$out" has libconfig/run-file-io-error "LC-file-io-error OK" "$out" has libconfig/run-no-error-after-ok "LC-no-error-after-ok OK" "$out" # stdio: write out, read back, and the FILE* forms. Every one of # config_read_file, config_write_file, config_read and config_write IS # coroutinized on this arm -- they suspend through stdio -- so this group is # the on-target guard for the coroutine rewrite over buffered I/O has libconfig/run-write-file "LC-write-file OK" "$out" has libconfig/run-reread-file "LC-reread-file OK" "$out" has libconfig/run-roundtrip-int "LC-roundtrip-int OK" "$out" has libconfig/run-roundtrip-int64 "LC-roundtrip-int64 OK" "$out" has libconfig/run-roundtrip-string "LC-roundtrip-string OK" "$out" has libconfig/run-roundtrip-hex-format "LC-roundtrip-hex-format OK" "$out" has libconfig/run-roundtrip-array "LC-roundtrip-array OK" "$out" has libconfig/run-roundtrip-list "LC-roundtrip-list OK" "$out" has libconfig/run-read-FILE "LC-read-FILE OK" "$out" has libconfig/run-read-FILE-value "LC-read-FILE-value OK" "$out" has libconfig/run-write-file-refused "LC-write-file-refused OK" "$out" # @include -- the only feature that opens a second file from inside the # lexer, so it exercises the scan-context stack and fopen mid-parse has libconfig/run-include-parse "LC-include-parse OK" "$out" has libconfig/run-include-own-value "LC-include-own-value OK" "$out" has libconfig/run-include-pulled-string "LC-include-pulled-string OK" "$out" has libconfig/run-include-pulled-int "LC-include-pulled-int OK" "$out" has libconfig/run-include-semicolon-is-error "LC-include-semicolon-is-error OK" "$out" has libconfig/run-include-missing-fails "LC-include-missing-fails OK" "$out" # the caller-owned-memory contract: the config hook, the per-setting hook, # and the destructor's call count has libconfig/run-config-hook "LC-config-hook OK" "$out" has libconfig/run-setting-hook "LC-setting-hook OK" "$out" has libconfig/run-destructor-called "LC-destructor-called OK" "$out" # depth and volume. 100 nested groups recurse the parser 100 times, and on # this arm that recursion is on a coroutine stack; the 1000-element and # 1000-member cases are read back one at a time, because a bad growth path # loses an entry rather than crashing has libconfig/run-deep-100-parse "LC-deep-100-parse OK" "$out" has libconfig/run-deep-100-walk "LC-deep-100-walk OK" "$out" has libconfig/run-deep-100-leaf "LC-deep-100-leaf OK" "$out" has libconfig/run-bigarray-parse "LC-bigarray-parse OK" "$out" has libconfig/run-bigarray-len "LC-bigarray-len OK" "$out" has libconfig/run-bigarray-values "LC-bigarray-values OK" "$out" has libconfig/run-bigarray-sum "LC-bigarray-sum OK" "$out" has libconfig/run-biggroup-add "LC-biggroup-add OK" "$out" has libconfig/run-biggroup-lookup "LC-biggroup-lookup OK" "$out" has libconfig/run-biggroup-len "LC-biggroup-len OK" "$out" # The probe's own tally and exit status, so a truncated run cannot pass by # having simply printed fewer lines. has libconfig/run-summary "LC-SUMMARY 130/130" "$out" has libconfig/run-exit "LC-EXIT rc=0" "$out" rm -rf "$probe" "$scratch" 2>/dev/null else bst_notok libconfig/probe-stage "could not stage $BST_DATA/libconfig-probe" fi