I have sent patches to GNU Autoconf to add new macros for testing Erlang modules, include files, and functions:
AC_ERLANG_CHECK_FUNC. I also sent a patch to fix the
AC_RUN_IFELSE macro which executes Erlang test code, so that this macro cleanly fails if the code doesn’t compile, and another patch to fix the
AC_COMPILE_IFELSE macro, which tests that Erlang test code compiles (this is a long known Autoconf bug).
AC_RUN_IFELSE patch has been committed so far. The other patches are functional, but the Autoconf maintainers would prefer a better integration with the other Autoconf macros, for instance by making Autoconf’s
AC_CHECK_HEADER macro working for Erlang code when the test language is set to Erlang, which could be used like that:
I agree that this is the right way to go, and it will benefit the other supported languages, but it will take me a lot more time to implement.
Ralf Wildenhus, one of GNU Autoconf’s maintainers, has also found a bug in the
AT_CHECK_EUNIT macro, which executes EUnit tests from a GNU Autotest testsuite: the macro was always failing when used with Erlang/OTP versions prior to R13. We finally fixed that bug, so that
AT_CHECK_EUNIT will work with prior versions of Erlang/OTP, when it will be first available in the next release of Autoconf. Users don’t have to worry about the details of that bug, but I just want to share below my frustration of using Erlang to implement command-line tools.
The problem with
AT_CHECK_EUNIT was that the Erlang module generated internally by
AT_CHECK_EUNIT for calling EUnit was calling function
init:stop/1 (taking an exit code as an argument). But that function was introduced only in R13, and only
init:stop/0 (without argument) was available in previous versions. There are only three high-level ways to stop the Erlang VM:
- by calling
halt/1, which takes the exit code as an argument, and abruptly exits the VM with that exit code without flushing the standard output;
- by calling
init:stop/0, which cleanly flushes the standard output, and always exits the VM with exit code 0;
- by calling
init:stop/1, which both cleanly flushes the standard output, and exits the VM with the exit code given as an argument, but is available only from version R13.
In AT_CHECK_EUNIT, we need both to return custom exit codes, to integrate with Autotest, and to flush the standard output, to let Autotest capture the whole output produced by EUnit. So only
init:stop/0 can be used. Internally, the Erlang test module was initially run within Autotest’s standard
AT_CHECK macro, basically like:
AT_CHECK([erl -s foobar start], )
AT_CHECK checks the exit code of the command in argument, and compares it to the expected exit code (here, 0). If it is the expected exit code, then the test succeeds. If the exit code is 77, the test is skipped, e.g. to indicate that a requirement to the test is not met. Otherwise, the test fails.
In the executed Erlang module, we determine that the exit code is 77 if EUnit is not available (i.e., if module
eunit cannot be loaded); otherwise if EUnit was run successfully and the EUnit test passed it is 0; otherwise it is 1. That exit code was passed to
init:stop/1 to exit the VM. In the fixed version of
AT_CHECK_EUNIT, the module now writes out the exit code into a temporary file, and then calls
init:stop/0 (and therefore the VM always exits with code 0 and normally never fails). The real exit code is then read from the file and checked in a subsequent test, like:
AT_CHECK([erl -s foobar start], ) AT_CHECK([test -f tempfile && (exit `cat tempfile`)])