Depending on a condition checked for in the configure script, I want to throw an error, thus aborting the target. (i.e. refuse to compile tests on 'make check', if the test framework is not installed)
The behavior I want to achieve is, that when you call make check, it will directly print diagnostics and exits.
However, if the Makefile contains:
# if check is missing, don't do anything at all
if MISSING_CHECK
check:
@echo "tests are disabled due to missing check"
$(error tests are disabled due to missing check)
endif
Automake answers this:
automake-1.16: warnings are treated as errors
Makefile.am:9: warning: error tests are disabled due to missing check: non-POSIX variable name
Makefile.am:9: (probably a GNU make extension)
make: *** [Makefile:347: ../Makefile.in] Error 1
So the question is, how I could portably can throw an error.
Thanks to @John Bollinger /Makefile.am now looks like this:
## Process this file with automake to produce Makefile.in
SUBDIRS = . src tests
# if check is missing, don't do anything at all
if MISSING_CHECK
check:
@echo "tests are disabled due to missing check"
@exit 1
endif
ACLOCAL_AMFLAGS = --install -I build-macro
And in /configure.ac there is:
AM_CONDITIONAL([MISSING_CHECK], [test x${enable_tests} = xno])
where enable_tests is either set to yes or no.
/tests/Makefile.am contains this:
# Process this file with automake to produce Makefile.in
AM_CFLAGS = -Wall -Wextra $(CHECK_CFLAGS)
TESTS =
TESTS += test_integer
check_PROGRAMS = $(TESTS)
[...]
If I execute make check, it currently looks like this:
Making check in .
make[1]: Entering directory '/tmp/build'
make[1]: Nothing to be done for 'check-am'.
make[1]: Leaving directory '/tmp/build'
Making check in src
make[1]: Entering directory '/tmp/build/src'
Making check in lib
make[2]: Entering directory '/tmp/build/src/lib'
make[2]: Nothing to be done for 'check'.
make[2]: Leaving directory '/tmp/build/src/lib'
make[2]: Entering directory '/tmp/build/src'
make[2]: Leaving directory '/tmp/build/src'
make[1]: Leaving directory '/tmp/build/src'
Making check in tests
make[1]: Entering directory '/tmp/build/tests'
make
make[2]: Entering directory '/tmp/build/tests'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/tmp/build/tests'
make check-TESTS
make[2]: Entering directory '/tmp/build/tests'
make[3]: Entering directory '/tmp/build/tests'
============================================================================
Testsuite summary for libvector 0.9
============================================================================
# TOTAL: 0
# PASS: 0
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
make[3]: Leaving directory '/tmp/build/tests'
make[2]: Leaving directory '/tmp/build/tests'
make[1]: Leaving directory '/tmp/build/tests'
tests are disabled due to missing check
make: *** [Makefile:820: check] Error 1
Which seams to tell a user, that all tests have succeed. But I want the error to be thrown before the Testsuite is tried to run.
Chosen solution
As it turned out, that overwriting the test-harness is quite difficult, because it is unconditionally added before any custom rules and to do so you have to depend on implementation defined characteristics of automake. See John Bollinger's answer for more details.
That's why instead of overwriting the test harness, I add only a single shell script to it, in case the tests aren't to be compiled.
/tests/Makefile.am:
# if check is missing, run script to inform the user of this
if MISSING_CHECK
check_SCRIPTS = no_test.sh
# allow the script to echo to stderr
AM_TESTS_FD_REDIRECT = 9>&2
endif
if !MISSING_CHECK
check_PROGRAMS =
check_PROGRAMS += test_integer
endif
TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
The script is generated by:
/configure.ac:
AC_CONFIG_FILES([tests/no_test.sh], [chmod +x tests/no_test.sh])
from:
/tests/no_test.sh.in:
#!/bin/bash
# Inform the user that tests are disabled and how to change that.
echo "No tests created due to missing check or user preference." >&2;
echo "No tests created due to missing check or user preference." >&9;
echo "To enable tests, run configure with --enable-tests=yes" >&2;
echo "To enable tests, run configure with --enable-tests=yes" >&9;
exit 1
Note that the user notification is issued twice as the stderr/stdout of the script is redirected to logfiles by the parallel test harness. &9 is then redirected to the real stderr by AM_TESTS_FD_REDIRECT = 9>&2. For the serial test harness it is simply directedto the real stderr and AM_TESTS_FD_REDIRECT is just ignored.
See: https://www.gnu.org/software/automake/manual/html_node/Testsuite-Environment-Overrides.html
The toplevel /Makefile.am is not changed at all.
The Autotools have a strong focus on portability across UNIX-like systems. You can fight that in various ways, but then the question arises of why you are using the Autotools in the first place.
However, Automake has better ability to analyze your
Makefile.amwith respect to portability than Autoconf has to analyze yourconfigure.acin the same light. If you write custom rules into yourMakefile.am(or into another file that itincludes) then you should stick to portable features, which mostly means those covered by the POSIX specifications formake. GNU extensions are largely out, especially all themake"functions" it provides, such as$(error).Generally speaking, in
makerecipes you should focus on shell features. In this case, unless you employ themakesyntax to specify otherwise, a recipe will fail, causingmaketo stop and report an error, if any of the commands in it fails. There is a standard command whose entire purpose is to fail:false. Alternatively,exit 1will terminate the shell with a failing exit status, which would serve the same purpose in this case. Thus, you might do something like this:Alternatively, you could consider whether it would be sufficient to just print the diagnostic message, without failing.
HOWEVER, what you actually want to do is alter the behavior of a target (
check) that belongs to Automake. This is allowed, but somewhat fraught. In particular, the documentation remarks thatYou have exercised exactly the least-advisable case for overriding Automake rules, and "inadvisable" here manifests as "it won't have the result that you probably expect".
If you dig into the Makefile generated by
configure, you will discover that the behavior you observe results from the fact that the top-levelchecktarget has a prerequisite (check-recursive) that implements the recursion. The prerequisite is built before the override recipe for targetcheckis executed.In a recursive Automake makefile, the local, non-recursive version of each standard target is named with an
-amsuffix. You can in fact see in your output thatcheck-amin the top directory is the first target built when youmake check.Armed with that knowledge, you could obtain the behavior you are after by overriding
check-aminstead ofcheck:But note that
To get the result you want this way, you have to process the top-level directory first, which often conflicts with what you want for other purposes.
We are now depending on undocumented Automake implementation details.
Generally speaking, it is supported to run
makein any of the subdirectories, and doing so will bypass any overrides or error generation implemented at the top level.Overall, my recommendation is don't do that.
DO have
configureemit a warning if libcheck is not available (AM_COND_IFcan help with that). This is the best and most timely way to notify a builder of the issue.DO suppress definition of any test cases when
CHECK_MISSINGis true, so that you don't hit builders with weird build failures in the event that they try amake checkdespite the warning fromconfigure.Possibly do even override the top-level
checktarget to emit an explanatory message about the absence of test cases, maybe something more prominent, such as:And if you feel you must, do cause
make checkto fail in this case, by the means already described.But DO NOT sweat the fact that an empty test suite is executed and summarized if a builder executes a
make checkdespite having already been notified that no tests are available.