# BST-TIMEOUT: 300 # one perl start for the runnability probe, plus a 49-file hash . "$BST_LIB" # cwautomacros ships 49 data files and no program, so `require` has nothing to # look up. What stands in for it is the x86-64 reference the recipe packaged # beside the payload, and the aclocal search path the port wires up. # # WHAT THIS SUITE CAN AND CANNOT ASSERT. The package's whole purpose is that # OTHER projects' configure scripts come out correct, and proving that means # running aclocal for real. HALF of that runs here: aclocal starts and # --print-ac-dir answers, which is the first half of the ticket's end-to-end read # and is asserted in section 7 unguarded. The other half -- an actual macro trace # -- dies one process further in, because splice(2) is ENOSYS # (linux-in-the-browser#167), GNU grep drains a pipe with splice when stdout is # /dev/null, and autom4te's GNU-m4 version check is exactly that idiom. Section 7 # probes the syscall rather than parsing autom4te's complaint, which names m4 -- # a working m4 1.4.19, asserted two cases earlier. # # So the functional proof was run on the BUILD HOST at do_install against the tree # this image was packaged from; section 6 reads that record back and section 2 # ties this image's bytes to it by sha256. The chain is: these bytes work, and # this image carries these bytes. # # THE REFERENCE IS A SECOND BUILD, NOT A RE-HASH. cwautomacros-x86_64.manifest is # generated in the recipe from cwautomacros-native -- an independently produced # x86-64 build of the same recipe at the same version -- so section 2 is the # ticket's own pass criterion ("each one's size and SHA-256 match the reference # the same recipe version produces on x86-64") and not a tautology. # # DO NOT ADD A BARE `m4 ` PARSE CHECK. The macro files are m4sugar input: # AC_DEFUN, m4_ifdef and their [ ] quoting are undefined to plain m4, so such a # check reds a good file. The sha256 in section 2 is the integrity check that # works, and the definedness sweep in section 6 is the one that proves the files # define what they declare. # $BST_CWA_ROOT prefixes every filesystem path so the suite can be scored on the # build host against a tree unpacked from the .debs; it is empty on target, which # is the configuration that ships. The ABSOLUTE forms below are separate on # purpose: what the dirlist must CONTAIN is the on-target path, whatever root the # files are being read from. ROOT=${BST_CWA_ROOT:-} CWA_ABS=/usr/share/cwautomacros M4_ABS=$CWA_ABS/m4 CWA=$ROOT$CWA_ABS M4=$ROOT$M4_ABS ACDIR=$ROOT/usr/share/aclocal ACDIR_ABS=/usr/share/aclocal REF=$ROOT/usr/libexec/cwautomacros-tests MANIFEST=$(bst_local "$REF/cwautomacros-x86_64.manifest") # tmpfs copy: a `done < "$MANIFEST"` runs in this shell (brintos/linux#73) PV=20110201 # The dropped-first-line absorber: brintos/linux#96 loses the first BST result # line of every suite, so the first case is one that asserts something already # true and costs nothing when it goes missing. Remove it when #96 closes. bst_ok cwautomacros/suite-canary # ------------------------------------------------ 1. the declared install surface check cwautomacros/datadir test -d "$CWA" check cwautomacros/m4dir test -d "$M4" check cwautomacros/version-file test -s "$CWA/version" check cwautomacros/autogen test -x "$CWA/scripts/autogen.sh" check cwautomacros/depcomp test -x "$CWA/scripts/depcomp.sh" check cwautomacros/template test -x "$CWA/templates/autogen.sh" check cwautomacros/doxygen-tmpl test -s "$CWA/templates/doxygen/Makefile.am" # Counted under this package's OWN directory, which it is the sole owner of. # /usr/share/aclocal is shared -- autoconf-archive alone puts 582 files there -- # so a count taken over that directory would measure the wrong tree. nf=$(find "$CWA" -type f 2>/dev/null | wc -l) check_eq cwautomacros/file-count 49 "$nf" nm4=$(ls "$M4"/*.m4 2>/dev/null | wc -l) check_eq cwautomacros/m4-count 40 "$nm4" # The build-time census, so a red here separates "the image installed a different # tree" from "the recipe packaged a different tree". check_eq cwautomacros/install-surface \ "cwautomacros-install-surface: files=49 m4=40 macros=42 version=20110131 pv=$PV" \ "$(cat "$REF/INSTALL-SURFACE" 2>&1)" # --------------------------- 2. size and sha256 against the x86-64 reference --- # The ticket's pass criterion, and the load-bearing section of this suite: # everything section 6 reads back is a statement about a build host, and this is # what ties it to the files in this image. check cwautomacros/manifest-shipped test -s "$MANIFEST" nref=$(wc -l < "$MANIFEST" 2>/dev/null) check_eq cwautomacros/manifest-count 49 "${nref:-0}" if [ -s "$MANIFEST" ] && command -v sha256sum >/dev/null 2>&1; then # One sha256sum -c over all 49, rather than 49 forks: process creation is the # expensive operation on this guest and the suite runs under a wall-clock bound. ck=${TMPDIR:-/tmp}/bst-cwa-ck.$$ while read -r h s f; do printf '%s %s\n' "$h" "$f"; done < "$MANIFEST" > "$ck" out=$( cd "$CWA" && sha256sum -c "$ck" 2>&1 ) nbad=$(printf '%s\n' "$out" | grep -c -v ': OK$') if [ "${nbad:-1}" = 0 ]; then bst_ok cwautomacros/sha256-all else bst_notok cwautomacros/sha256-all \ "$nbad of 49 files do not match the x86-64 reference: $(_bst_1line "$(printf '%s\n' "$out" | grep -v ': OK$' | head -5)")" fi rm -f "$ck" # Sizes are stated separately because the ticket states them separately, and # because a size mismatch localises a truncated install faster than a hash does. sz=${TMPDIR:-/tmp}/bst-cwa-sz.$$ ( cd "$CWA" && cut -d' ' -f3 "$MANIFEST" | xargs wc -c ) > "$sz" 2>&1 # Joined in one awk rather than a shell loop, for two reasons: 49 forks is the # expensive thing on this guest, and `wc -c` INDENTS its counts -- a shell # ${a%% *} against a leading-space field yields the empty string and reports # every file as a mismatch, which is exactly what the first run of this suite # did (49 of 49, against a payload whose hashes had just all matched). nsz=$(awk 'NR==FNR { want[$3]=$2; next } $2 == "total" { next } { got[$2]=$1 } END { n=0; for (f in want) if (want[f] != got[f]) n=n+1; print n }' \ "$MANIFEST" "$sz" 2>/dev/null) check_eq cwautomacros/size-all 0 "${nsz:-49}" rm -f "$sz" else bst_skip cwautomacros/sha256-all "no manifest or no sha256sum on this image, so the payload cannot be tied to the x86-64 reference" bst_skip cwautomacros/size-all "no manifest or no sha256sum on this image" fi # Named spot-checks, so a red says WHICH file rather than only that the set moved. # CW_AUTOMACROS.m4 is the one every consumer's configure.ac calls first; # scripts/autogen.sh is the one the recipe has to sed a build path out of; version # is the one whose contents autogen.sh tells the consumer to pass to the gate. check_out cwautomacros/spot-automacros "AC_DEFUN([CW_AUTOMACROS]" cat "$M4/CW_AUTOMACROS.m4" check_out cwautomacros/spot-gate-number "if test $PV -lt \$minver" cat "$M4/CW_AUTOMACROS.m4" check_out cwautomacros/spot-cwflags "ACLOCAL_CWFLAGS=\"-I \${CWAUTOMACROSPREFIX-/usr}/share/cwautomacros/m4\"" cat "$M4/CW_AUTOMACROS.m4" # ------------------------------------------------- 3. the declared macro surface # Read out of the installed files. Both definition forms count, and the count is # 42 across 40 files: CW_BUG_REDEFINES.m4 and CW_DEFINE_TYPE.m4 each declare a # second macro, which a per-file count would miss. sed -n 's/^AC_DEFUN(\[\([A-Za-z0-9_]*\)\].*/\1/p; s/^m4_defun(\[\([A-Za-z0-9_]*\)\].*/\1/p' \ "$M4"/*.m4 2>/dev/null | sort -u > "${TMPDIR:-/tmp}/bst-cwa-macros.$$" 2>/dev/null n=$(wc -l < "${TMPDIR:-/tmp}/bst-cwa-macros.$$" 2>/dev/null || echo 0) check_eq cwautomacros/macro-count 42 "$n" # The set, not just the size -- an upstream bump that swapped one macro for # another would keep the count. The reference was generated in the recipe from the # tree this image was packaged from, so a mismatch means the installed files are # not the packaged ones. check cwautomacros/macro-set \ cmp -s "${TMPDIR:-/tmp}/bst-cwa-macros.$$" "$REF/cwautomacros-macros.list" rm -f "${TMPDIR:-/tmp}/bst-cwa-macros.$$" # ------------------------------------------------------------- 4. the dirlist # The one thing this port adds to the payload. Upstream installs NOTHING into the # aclocal directory -- its consumers pass -I , which is # what CW_AUTOMACROS's ACLOCAL_CWFLAGS carries -- so without this file the image's # aclocal cannot reach these macros at all. automake reads $acdir/dirlist and # appends every directory named there to its system search path. check cwautomacros/acdir test -d "$ACDIR" check cwautomacros/dirlist test -s "$ACDIR/dirlist" check_eq cwautomacros/dirlist-names-m4dir "$M4_ABS" "$(cat "$ACDIR/dirlist" 2>&1)" # aclocal SKIPS a dirlist entry it cannot stat, so an entry naming a directory # that is not installed is inert rather than broken -- and inert is the failure # that reads exactly like success. dl=$(cat "$ACDIR/dirlist" 2>/dev/null) # The empty case is called out rather than folded into `test -d`: an absent or # empty dirlist makes "$ROOT$dl" the root itself, which is a directory, so the # obvious one-liner passes on exactly the input the case exists to catch. if [ -n "$dl" ] && [ -d "$ROOT$dl" ]; then bst_ok cwautomacros/dirlist-target-exists else bst_notok cwautomacros/dirlist-target-exists \ "the dirlist names '$dl', which is not an installed directory -- aclocal skips an entry it cannot stat, so this would be inert rather than broken" fi check cwautomacros/dirlist-target-populated \ test -s "$ROOT$dl/CW_AUTOMACROS.m4" # The macros are deliberately NOT copied into $ACDIR. Asserted rather than left # implicit: a future change that copies them there would put 40 files into a # shared directory and silence the dirlist without anything going red. if [ -e "$ACDIR/CW_AUTOMACROS.m4" ]; then bst_notok cwautomacros/macros-not-copied \ "CW_AUTOMACROS.m4 is in $ACDIR as well as $M4; this port reaches the macros through dirlist and copying them duplicates 40 files into a shared directory" else bst_ok cwautomacros/macros-not-copied fi # ------------------------------------------------------- 5. the version number # The installed version file is NOT the release label and must not be assumed to # be: poky regenerates it from SOURCE_DATE_EPOCH for reproducibility, so it reads # the tarball's mtime day rather than 20110201. That is harmless only while it # stays at or below the number baked into CW_AUTOMACROS.m4, because # scripts/autogen.sh tells every consumer to pass this file's contents to # CW_AUTOMACROS([...]), whose body errors out when asked for more than it carries. ver=$(cat "$CWA/version" 2>/dev/null) check_eq cwautomacros/version-value 20110131 "$ver" if [ -n "$ver" ] && [ "$ver" -le "$PV" ] 2>/dev/null; then bst_ok cwautomacros/version-below-gate else bst_notok cwautomacros/version-below-gate \ "the version file says '$ver', above the $PV baked into CW_AUTOMACROS.m4 -- every consumer following scripts/autogen.sh would be told 'cwautomacros version $ver or later is required'" fi # ------------------------------------------- 6a. no build path reached the image # The Makefile substitutes @INSTALLPREFIX@ with ${D}${prefix} in scripts/*.sh and # the recipe seds ${D} back out. Assert the RESULT: a second script growing an # @INSTALLPREFIX@ would ship a build path here and nothing else would say so. check_out cwautomacros/autogen-prefix "-I /usr/share/cwautomacros/m4" cat "$CWA/scripts/autogen.sh" if grep -rq -e '@INSTALLPREFIX@' -e '/tmp-glibc/work' "$CWA" 2>/dev/null; then bst_notok cwautomacros/no-buildpath \ "an installed file carries an unsubstituted @INSTALLPREFIX@ or a build path: $(grep -rl -e '@INSTALLPREFIX@' -e '/tmp-glibc/work' "$CWA" 2>/dev/null | head -3 | tr '\n' ' ')" else bst_ok cwautomacros/no-buildpath fi # ------------------------------- 6b. the build-host oracle, read back on target check cwautomacros/oracle-shipped test -s "$REF/cwautomacros-oracle.txt" check_out cwautomacros/oracle-complete "CWA-ORACLE-END" cat "$REF/cwautomacros-oracle.txt" # The definedness sweep and its control. The control is not decoration: with the # macro files NOT included the same sweep must find nothing, or the sweep is # reading macros from somewhere else and its 42/0 says nothing at all. check_out cwautomacros/oracle-sweep "CWA-SWEEP defined=42 missing=0" cat "$REF/cwautomacros-oracle.txt" check_out cwautomacros/oracle-sweep-control "CWA-SWEEP-CONTROL defined=0 missing=42" cat "$REF/cwautomacros-oracle.txt" # The expansion arm through upstream's documented -I path. `unexpanded=0` is the # assertion; the control beside it is what makes it mean anything, because # autoconf exits 0 EITHER WAY -- it copies calls it cannot resolve straight into # ./configure. Measured on the build host: 139,650 bytes and 0 unexpanded with the # macros reachable, 73,117 bytes and 4 without, rc=0 in both. check_out cwautomacros/oracle-expand "unexpanded=0" \ sed -n 's/^CWA-EXPAND //p' "$REF/cwautomacros-oracle.txt" # subst=yes is a separate statement from unexpanded=0: ACLOCAL_CWFLAGS is # CW_AUTOMACROS's own AC_SUBST output variable, so it says the macro BODY landed # rather than only that the token disappeared. check_out cwautomacros/oracle-expand-subst "subst=yes" \ sed -n 's/^CWA-EXPAND //p' "$REF/cwautomacros-oracle.txt" ctl=$(sed -n 's/^CWA-EXPAND-CONTROL //p' "$REF/cwautomacros-oracle.txt" 2>/dev/null | head -1) case "$ctl" in *unexpanded=0*|"") bst_notok cwautomacros/oracle-expand-control \ "the expansion control left nothing unexpanded ('$ctl'), so it did not reproduce the silent failure the arm above asserts the absence of" ;; *) bst_ok cwautomacros/oracle-expand-control ;; esac # The dirlist arm and its control -- aclocal reaching the macros with NO -I at # all, which is the end-to-end read this port exists to make true, run for real # on the build host. check_out cwautomacros/oracle-dirlist "CWA-DIRLIST found=yes" cat "$REF/cwautomacros-oracle.txt" check_out cwautomacros/oracle-dirlist-control "CWA-DIRLIST-CONTROL found=no" cat "$REF/cwautomacros-oracle.txt" check_out cwautomacros/oracle-print-ac-dir "print_ac_dir=matches-acdir" cat "$REF/cwautomacros-oracle.txt" # CW_AUTOMACROS's own version gate, from both sides, run as a real ./configure. check_out cwautomacros/oracle-gate-accept "CWA-GATE-ACCEPT accepted" cat "$REF/cwautomacros-oracle.txt" check_out cwautomacros/oracle-gate-reject "CWA-GATE-REJECT rejected" cat "$REF/cwautomacros-oracle.txt" check_out cwautomacros/oracle-gate-message "cwautomacros version 99999999 or later is required" \ cat "$REF/cwautomacros-oracle.txt" # The x86-64 comparison the ticket asked for, recorded at build time. Section 2 # re-runs its hashes here; this reads back the recipe's own verdict, which also # names the one file that legitimately differs and why. check cwautomacros/native-cmp-shipped test -s "$REF/cwautomacros-native.cmp" check_out cwautomacros/native-count "REFERENCE-FILES 49" cat "$REF/cwautomacros-native.cmp" check_out cwautomacros/native-arch "NATIVE-BUILD cwautomacros-native $PV on x86_64" cat "$REF/cwautomacros-native.cmp" # scripts/autogen.sh is the one file that cannot be byte-identical: upstream's # Makefile substitutes @INSTALLPREFIX@ with ${D}${prefix}, and a native recipe's # ${prefix} IS its recipe sysroot. The recipe normalises that one prefix and # requires the rest to match, which names the tolerated difference instead of # exempting the file. check_out cwautomacros/native-autogen "IDENTICAL-AFTER-PREFIX-NORMALISATION scripts/autogen.sh" \ cat "$REF/cwautomacros-native.cmp" nd=$(grep -c '^DIFFERS ' "$REF/cwautomacros-native.cmp" 2>/dev/null || true) check_eq cwautomacros/native-no-differs 0 "${nd:-1}" # ------------------------------------- 7. the functional half, attempted here # m4 is the C half of the autotools chain and runs fine on this arm. Asserted # first, so a red below is localised to the perl half rather than read as "the # autotools chain is broken" -- and autoconf's own diagnostic names m4 wrongly. require m4 cwautomacros/m4-present check_out cwautomacros/m4-runs "GNU M4" m4 --version # Absent and present-but-unable-to-start are different findings and get different # verbs: automake is in this image's manifest, so an absent aclocal would be a # packaging change rather than the platform defect below. if ! command -v aclocal >/dev/null 2>&1; then bst_skip cwautomacros/aclocal-runnable "aclocal is not installed on this image" bst_skip cwautomacros/aclocal-exit-status "aclocal is not installed on this image" bst_skip cwautomacros/aclocal-print-ac-dir "aclocal is not installed on this image" bst_skip cwautomacros/autom4te-usable "aclocal is not installed on this image" bst_skip cwautomacros/aclocal-finds-macros "aclocal is not installed on this image" exit 0 fi # aclocal STARTS on this arm, and that is measured rather than assumed. The # sibling 90-automake.test guards its whole body behind linux-in-the-browser#154 # (perl aborting in glibc's allocator while compiling a core module), and that # guard does NOT fire here: aclocal prints its banner normally. Attributing this # suite's red to #154 would send a reader to the wrong defect, so the probe is # kept and asserted on its own. # # ASSERTED ON THE OUTPUT, NOT THE EXIT STATUS, and the split is the finding # rather than a convenience. On this image aclocal does its whole job, prints the # right answer, and THEN dies in perl's global destruction -- # `panic: magic_killbackrefs (flags=87a)`, linux-in-the-browser#93 -- so it exits # 255 having succeeded. `check_out` requires rc=0, so using it here reds a working # tool; that is exactly what this suite did on its first verify run before the two # statements were separated. vout=$(aclocal --version 2>&1); vrc=$? case "$vout" in *"GNU automake"*) bst_ok cwautomacros/aclocal-runnable ;; *) bst_notok cwautomacros/aclocal-runnable "rc=$vrc $(_bst_1line "$vout")" ;; esac # The exit status is its own case so the defect is visible rather than tolerated # in silence. Left FAILING and attributed: it flips green by itself when #93 # closes, which is the regression signal keeping it costs. if [ "$vrc" = 0 ]; then bst_ok cwautomacros/aclocal-exit-status else bst_notok cwautomacros/aclocal-exit-status \ "linux-in-the-browser#93: aclocal printed its banner correctly and then exited $vrc in perl's global destruction (panic: magic_killbackrefs). Measured on the same boot: perl -e, m4 --version and autoconf --version all exit 0, so this is aclocal's perl teardown, not the shell or the image" fi # THE FIRST HALF OF THE TICKET'S END-TO-END READ, AND IT PASSES ON TARGET. # --print-ac-dir is handled in aclocal's argument parser and exits before any # autom4te is spawned, so it survives the defect below. It names the system acdir; # section 4 has already asserted that the dirlist making these macros reachable # lives in exactly that directory. Compared on the OUTPUT for the #93 reason # above: this call prints /usr/share/aclocal and then exits 255. acd=$(aclocal --print-ac-dir 2>/dev/null) check_eq cwautomacros/aclocal-print-ac-dir "$ACDIR_ABS" "$acd" # BRINTOS-WORKAROUND: linux-in-the-browser#167 remove -- the second half of the # read cannot run while splice(2) is ENOSYS. Delete this block when #167 closes; # the case it guards needs no edit and the suite returns to its full green on its # own. # # The one-line reproducer rather than an inference from aclocal's output. Two # details are load-bearing: stdout must be /dev/null (anywhere else and grep never # reaches its splice path) and the pattern must MATCH (grep only drains, and so # only splices, once it has decided it can stop reading). The chain measured on # this image, 2026-08-23, with the macros reachable both ways: # # grep: (standard input): Function not implemented # autom4te: error: need GNU m4 1.4 or later: m4 # aclocal: error: autom4te failed with exit status: 1 # # -- so autom4te rejects the m4 1.4.19 that cwautomacros/m4-runs has just shown # working, and every aclocal TRACE dies with it. Identical with `-I` and without, # which is what says the dirlist is not what is failing. sperr=$(echo bst-splice-probe | grep bst-splice-probe 2>&1 >/dev/null); sr=$? if [ "$sr" != 0 ]; then bst_notok cwautomacros/autom4te-usable \ "linux-in-the-browser#167: splice(2) is ENOSYS, so 'cmd | grep P >/dev/null' fails (rc=$sr $(_bst_1line "$sperr")) and autom4te rejects a working m4 -- no aclocal trace can run" bst_skip cwautomacros/aclocal-finds-macros \ "blocked by linux-in-the-browser#167 -- the dirlist is installed and asserted in section 4, and aclocal was driven through it for real on the build host (cwautomacros/oracle-dirlist)" exit 0 fi bst_ok cwautomacros/autom4te-usable # From here on the target can do what the oracle did. Reached only once #167 is # fixed; written now so that day needs no edit to this file. tmp=${TMPDIR:-/tmp}/bst-cwa.$$ mkdir -p "$tmp" && cd "$tmp" || { bst_notok cwautomacros/tmpdir "cannot create $tmp"; exit 0; } : > fixture.txt cat > configure.ac <<'ACEOF' AC_INIT([bst-cwa],[1.0]) AC_CONFIG_SRCDIR([fixture.txt]) CW_AUTOMACROS([20110131]) AC_OUTPUT ACEOF # No -I: the whole point is that the system search path reaches the macros. aclocal >aclocal.log 2>&1 if [ -s aclocal.m4 ]; then check_out cwautomacros/aclocal-finds-macros "CW_AUTOMACROS" cat aclocal.m4 else # perl on this arm prints a seven-line locale complaint before anything it has # to say, and repeats it per process -- so the HEAD of this log is never the # error. Report the tail, with that block filtered out. det=$(grep -v -e 'locale' -e 'LANGUAGE' -e 'LC_ALL' -e 'LANG =' -e 'are supported and installed' aclocal.log 2>/dev/null | grep -v '^[[:space:]]*$' | tail -3 | tr '\n' ' ') bst_notok cwautomacros/aclocal-finds-macros "aclocal produced no aclocal.m4: $(_bst_1line "$det")" fi cd /; rm -rf "$tmp"