# BST-TIMEOUT: 1800 # every case forks perl and m4; aclocal scans the macro dir and the generated configure re-forks both per probe . "$BST_LIB" require automake automake/present tmp=${TMPDIR:-/tmp}/bst-automake.$$ mkdir -p "$tmp" || { bst_notok automake/tmpdir "cannot create $tmp"; return 2>/dev/null || exit 0; } cd "$tmp" || { bst_notok automake/chdir "cannot cd $tmp"; return 2>/dev/null || exit 0; } # ---------------------------------------------------------------- 1. the tools # automake is a perl program that drives m4 through aclocal and hands off to # autoconf. None of the three is optional and none is statically bound into it, # so a missing one turns every case below into a fork failure whose message names # the interpreter rather than automake -- assert all of them up front so that # shape is one named red instead of forty anonymous ones. autoconf is here # because automake's RDEPENDS names it, which is how it reaches this image today. # # Everything in this section only READS the filesystem. Nothing here starts a # perl program; the guard in 1a is what decides whether anything may. check automake/perl-present test -x /usr/bin/perl check automake/m4-present test -x /usr/bin/m4 check automake/aclocal-present test -x /usr/bin/aclocal check automake/autoconf-present test -x /usr/bin/autoconf check automake/autoheader-present test -x /usr/bin/autoheader # The versioned names are a separate packaging fact from the unversioned ones, # and they are the names the generated rules actually invoke: a Makefile.in built # with --add-missing re-runs `automake-1.16`, not `automake`, through the # `missing` wrapper. A package that shipped only the unversioned pair would pass # every check above and fail on the first regenerating make. # # Matched by GLOB, not by the pinned 1.16: the version is the recipe's to choose # and a poky uprev must not turn this suite red for having moved a correct file. # What is under test is that the versioned pair EXISTS beside the unversioned one. check automake/versioned-automake sh -c 'for f in /usr/bin/automake-1.*; do [ -x "$f" ] && exit 0; done; exit 1' check automake/versioned-aclocal sh -c 'for f in /usr/bin/aclocal-1.*; do [ -x "$f" ] && exit 0; done; exit 1' # The macro library and the aux programs are separate install paths from the # program, and a package that shipped the perl but not the m4 would pass every # --version check and fail the moment aclocal had to resolve AM_INIT_AUTOMAKE. # Asserted from the filesystem rather than from `aclocal --print-ac-dir`, which # would need a perl to start: this is the half of the port that IS measurable on # this arm today, and it must not be lost behind the guard below. The tool's own # answer is cross-checked against these paths in 1b, once perl is known to run. amdir= for d in /usr/share/automake-1.*; do [ -d "$d" ] && amdir=$d; done check automake/aclocal-dir test -d /usr/share/aclocal check automake/aclocal-macros sh -c 'ls /usr/share/aclocal/*.m4 >/dev/null 2>&1' check automake/amdir test -n "$amdir" check automake/aux-am-install-sh test -s "$amdir/install-sh" check automake/aux-am-missing test -s "$amdir/missing" check automake/aux-am-compile test -s "$amdir/compile" check automake/aux-am-depcomp test -s "$amdir/depcomp" check automake/aux-am-test-driver test -s "$amdir/test-driver" # The rule fragments are what automake actually pastes into a Makefile.in; the # aux programs above would all be present in a package that shipped none of them. check automake/am-fragments sh -c "ls '$amdir'/am/*.am >/dev/null 2>&1" # m4 is the C half of the chain and runs fine on this arm. Asserted before the # guard so that a red below is localised to the perl half rather than read as # "the autotools chain is broken". check_out automake/m4-version "GNU M4" m4 --version # ------------------------------ 1a. can any automake program START? ---------- # BRINTOS-WORKAROUND: linux-in-the-browser#154 remove -- perl aborts in glibc's # allocator while compiling any core module, so automake and aclocal die before # they parse an argument; delete this guard and section 2 onward runs # unconditionally again the day #154 closes. # # automake 1.16.5 is perl end to end, and so is every program this suite hands # off to: aclocal, autoheader and autoconf. On this arm perl aborts in the glibc # allocator while COMPILING any core module -- `mremap_chunk(): invalid pointer`, # `corrupted size vs. prev_size` or `realloc(): invalid next size`, rc=127 -- # before a line of automake's own code runs. `m4 --version` above answers # normally on the same boot, which is what places the defect in perl; and the # packaging cases above stay green, which is what keeps requirement 2 measured. # # This is a guard, NOT a skip of an inconvenient case: the probe is left FAILING # and attributed, so it flips green by itself when #154 closes, which is the # regression signal this suite is bought for. What it prevents is running the # forty cases below anyway. Measured on the sibling autoconf port unguarded: 43 # reds of 54, and the host guest process at a 3.7 GiB peak -- the growth #154's # rsnapshot comment records at ~2400 MiB/min, which costs every suite scheduled # after this one in the same sweep. An unguarded perl program is a hazard to the # run, not a red of its own. vout=$(automake --version 2>&1); vrc=$? case "$vout" in *"GNU automake"*) bst_ok automake/version ;; *) bst_notok automake/version \ "rc=$vrc $(_bst_1line "$vout") -- perl cannot compile its core modules on this arm (linux-in-the-browser#154), so no automake program starts" # Named rather than silent: the ticket's headline criterion is a FULL NATIVE # BUILD on target -- aclocal, autoheader, automake, autoconf, then configure, # make, make check, make install, make dist and the clean rules, ending by # running the installed artifact -- and that is exactly what could not be # measured. A suite that merely stopped here would report its packaging # greens and read as a pass. bst_notok automake/native-build-unverified \ "not run: no automake program can start (linux-in-the-browser#154) -- the full-native-build criterion is unverified on wasm32-hwjs" cd / rm -rf "$tmp" exit 0 ;; esac # ------------------------------------------- 1b. past the guard: perl runs check_out automake/aclocal-version "GNU automake" aclocal --version check_out automake/help "--add-missing" automake --help # Now that a perl program can start, cross-check the tool's own idea of where its # macros live against the path asserted from the filesystem in section 1. acdir=$(aclocal --print-ac-dir 2>/dev/null) check_eq automake/aclocal-dir-agrees /usr/share/aclocal "$acdir" # ------------------------------------------------------------- 2. the fixture # A SCRIPT program, not a compiled one, and the reason is structural: this image # has no target C compiler (the wasm32 toolchain is a cross toolchain living on # the build host), so a Makefile.am with bin_PROGRAMS would fail here for a # reason that says nothing about automake. bin_SCRIPTS drives the same generated # machinery that matters on target -- the all/check/install/uninstall/dist/clean # rule set, VPATH, DESTDIR and the test harness -- without one. The compile and # link rules are reported as an explicit skip at the end rather than omitted. cat > configure.ac <<'ACEOF' AC_INIT([bst-automake], [1.0], [bst@example.invalid]) AC_CONFIG_SRCDIR([greet.in]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign]) AC_SUBST([GREETING], [hello-from-automake]) AC_DEFINE([BST_MARKER], [1], [defined by the brintOS automake self-test]) AC_CHECK_PROGS([SED_PROG], [sed], [none]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT ACEOF # The build rule substitutes a literal token rather than an @-placeholder, so # nothing here depends on whether config.status also processes the template -- # what is under test is the generated Makefile's own rule execution. cat > Makefile.am <<'AMEOF' bin_SCRIPTS = greet CLEANFILES = greet TESTS = check-greet.sh dist_noinst_DATA = greet.in dist_check_SCRIPTS = check-greet.sh greet: greet.in Makefile sed -e 's|__GREETING__|$(GREETING)|g' -e 's|__VERSION__|$(VERSION)|g' \ $(srcdir)/greet.in > $@ chmod +x $@ AMEOF cat > greet.in <<'GEOF' #!/bin/sh echo "greeting=__GREETING__" echo "version=__VERSION__" GEOF # Honours BST_GREET_FAIL so the harness's failure path can be exercised too: a # test suite that cannot fail is not evidence that it can pass. cat > check-greet.sh <<'CEOF' #!/bin/sh out=$(./greet) || exit 1 case "$out" in *greeting=hello-from-automake*) ;; *) exit 1 ;; esac [ -n "$BST_GREET_FAIL" ] && exit 1 exit 0 CEOF chmod +x check-greet.sh # --------------------------------------------------- 3. aclocal builds aclocal.m4 rm -f aclocal.m4 check automake/aclocal aclocal check automake/aclocal-out test -s aclocal.m4 # The macro really came from the library, not from thin air: AM_INIT_AUTOMAKE is # defined in aclocal.m4, not merely referenced by configure.ac. check_out automake/aclocal-am-init "AM_INIT_AUTOMAKE" cat aclocal.m4 # ------------------------------------------ 3b. autoheader builds config.h.in # Not optional and not cosmetic: AC_CONFIG_HEADERS makes config.h.in a REQUIRED # input to automake, which refuses with "required file 'config.h.in' not found" # and writes no Makefile.in at all if it is absent. That is why the chain here is # aclocal -> autoheader -> automake -> autoconf and not the shorter order. rm -f config.h.in check automake/autoheader autoheader check automake/autoheader-out test -s config.h.in check_out automake/autoheader-undef "#undef BST_MARKER" cat config.h.in # ------------------------------------------- 4. automake generates Makefile.in rm -f Makefile.in check automake/generate automake --add-missing --copy --foreign check automake/makefile-in test -s Makefile.in check automake/aux-install-sh test -s install-sh check automake/aux-missing test -s missing # The generated Makefile.in is a rule set, not a copy of Makefile.am. Assert the # rules the port exists to provide -- a Makefile.in missing install-am is a # plausible-looking file that cannot install anything. check_out automake/rule-all "all-am" cat Makefile.in check_out automake/rule-install "install-am" cat Makefile.in check_out automake/rule-clean "clean-am" cat Makefile.in check_out automake/rule-dist "distdir" cat Makefile.in check_out automake/rule-check "check-TESTS" cat Makefile.in check_out automake/rule-uninstall "uninstall-am" cat Makefile.in # Generation is deterministic -- same input, byte-identical output. automake --foreign >/dev/null 2>&1 cp -f Makefile.in det1 automake --foreign >/dev/null 2>&1 cp -f Makefile.in det2 check automake/generate-deterministic cmp -s det1 det2 # --------------------------------------------- 5. autoconf turns it into configure rm -f configure check automake/autoconf autoconf check automake/configure-exists test -s configure # ---------------------- 6. configure runs -- in a scratch dir, so also VPATH # @srcdir@ has to come back as '..' rather than '.', which is the substitution # most likely to be wrong and the one a same-directory run structurally cannot see. rm -rf scratch && mkdir -p scratch if cd scratch 2>/dev/null; then out=$(sh ../configure --prefix=/usr 2>&1); rc=$? if [ "$rc" -eq 0 ]; then bst_ok automake/configure-run elif bst_execfail "$out"; then bst_unrun automake/configure-run "$out" else bst_notok automake/configure-run "rc=$rc $(_bst_1line "$out")"; fi check automake/config-status test -x config.status check automake/makefile-created test -s Makefile check automake/config-log test -s config.log check automake/config-h test -s config.h check_out automake/config-h-define "#define BST_MARKER 1" cat config.h check_out automake/subst-srcdir "srcdir = .." cat Makefile check_out automake/subst-version "VERSION = 1.0" cat Makefile # Asserting the named substitutions one by one cannot catch a placeholder # nobody thought to name; this catches all of them at once. n=$(grep -c '@[A-Za-z_][A-Za-z0-9_]*@' Makefile 2>/dev/null || true) check_eq automake/subst-complete 0 "$n" # --------------------- 7. make -- the generated rules build the program check automake/make make check automake/make-built test -x greet check_out automake/make-output "greeting=hello-from-automake" sh -c './greet' check_out automake/make-version "version=1.0" sh -c './greet' # A second make must not re-run the build recipe -- the generated dependency on # greet.in/Makefile is what stops it. Assert that the recipe did not run rather # than matching make's own "Nothing to be done" wording, which this make does # not print for a rule reached through all-am. out=$(make 2>&1) case "$out" in *"sed -e"*) bst_notok automake/make-idempotent "rebuilt greet on an up-to-date tree" ;; *) bst_ok automake/make-idempotent ;; esac # ------------------- 8. make check -- automake's own TESTS harness check_out automake/make-check "PASS: check-greet" sh -c 'make check' check_out automake/check-summary "TOTAL: 1" sh -c 'make check 2>&1' # ...and the harness really adjudicates, rather than printing PASS regardless. rm -f check-greet.log check-greet.trs test-suite.log out=$(BST_GREET_FAIL=1 make check 2>&1); rc=$? if [ "$rc" -ne 0 ]; then bst_ok automake/check-detects-failure else bst_notok automake/check-detects-failure "a failing TESTS entry still exited 0"; fi rm -f check-greet.log check-greet.trs test-suite.log # ------------------- 9. make install -- into a DESTDIR, then RUN what landed # Running the INSTALLED copy is the pass criterion: it is the only thing that # proves the install rules placed a working artifact, not merely a file. dest=$tmp/destdir rm -rf "$dest" check automake/make-install sh -c "make install DESTDIR='$dest'" check automake/installed test -x "$dest/usr/bin/greet" check_out automake/installed-runs "greeting=hello-from-automake" sh -c "'$dest/usr/bin/greet'" # ------------------- 10. make dist -- the distribution rules check automake/make-dist make dist check automake/dist-tarball test -s bst-automake-1.0.tar.gz check_out automake/dist-contents "bst-automake-1.0/Makefile.am" \ sh -c 'tar tzf bst-automake-1.0.tar.gz' # greet.in was named dist_noinst_DATA, so the distribution has to carry it. check_out automake/dist-includes-src "bst-automake-1.0/greet.in" \ sh -c 'tar tzf bst-automake-1.0.tar.gz' # ------------------- 11. uninstall / clean / distclean check automake/make-uninstall sh -c "make uninstall DESTDIR='$dest'" check automake/uninstalled sh -c "! test -e '$dest/usr/bin/greet'" check automake/make-clean make clean check automake/clean-removed sh -c '! test -e greet' # distclean goes last: it removes the Makefile every case above needs. check automake/make-distclean make distclean check automake/distclean-removed sh -c '! test -e Makefile' cd "$tmp" || true else bst_notok automake/configure-run "cannot cd $tmp/scratch" fi # ------------------------------------------- 12. the compile/link rules # Recorded, not omitted. bin_PROGRAMS is the one primary this image cannot # exercise, and a suite that quietly left it out would read as full coverage. bst_skip automake/compile-link \ "no target C compiler on this image (the wasm32 toolchain is cross, on the build host); bin_PROGRAMS compile/link rules are not runnable on target -- the SCRIPTS, TESTS, install, dist and clean rules above are" # ---------------------------------------------- 13. exit-status contracts # A tool that diagnoses nothing is worse than one that fails: assert the status # AND that the message names the problem. rm -rf empty && mkdir -p empty out=$(cd empty && automake 2>&1); rc=$? if [ "$rc" -ne 0 ]; then bst_ok automake/rc-no-configure-ac else bst_notok automake/rc-no-configure-ac "missing configure.ac exited 0"; fi case "$out" in *configure.ac*|*configure.in*) bst_ok automake/msg-no-configure-ac ;; *) bst_notok automake/msg-no-configure-ac "$(_bst_1line "$out")" ;; esac out=$(automake --no-such-option-xyz 2>&1); rc=$? if [ "$rc" -ne 0 ]; then bst_ok automake/rc-bad-option else bst_notok automake/rc-bad-option "unknown option exited 0"; fi # A Makefile.am using a conditional configure.ac never declared is a user error # automake must diagnose BY NAME, not pass through into a broken Makefile.in. # (An unknown `bin_` primary is deliberately NOT the case used here: automake # accepts bin_NOSUCHPRIMARY as an ordinary variable and exits 0, so asserting a # failure on it would be asserting something untrue.) config.h.in is copied in # with the rest so the run fails for the conditional and not for a missing input. rm -rf badam && mkdir -p badam cp configure.ac aclocal.m4 config.h.in badam/ 2>/dev/null : > badam/greet.in printf 'if BST_NOSUCH_COND\nbin_SCRIPTS = greet\nendif\n' > badam/Makefile.am out=$(cd badam && automake --foreign 2>&1); rc=$? if [ "$rc" -ne 0 ]; then bst_ok automake/rc-undefined-conditional else bst_notok automake/rc-undefined-conditional "undefined conditional exited 0"; fi case "$out" in *BST_NOSUCH_COND*) bst_ok automake/msg-undefined-conditional ;; *) bst_notok automake/msg-undefined-conditional "$(_bst_1line "$out")" ;; esac cd / rm -rf "$tmp"