AC-Archive
Autoconf Macro Archive

ac-archive.sf.net: - Project CVS - Download
Macro Index
- AM Support
- C++ Support
- C Support
- Fortran Support
- Java Support
- Cross Compilation
- Installed Packages
- Miscellaneous
- LaTeX Support
- Uncategorized
- archive macros
- adl's macros
- bkorb's macros
- guidod's macros
- latex's macros
- other's macros
- rleigh's macros
- obsoleted macros
- released macros
- search index

Documentation
- Contribute!
- History
- acincludedir m4
- acinclude (tool)
- macro howto
- ax tricks
- maintainers
- License
- Topics

generated...
2007-08-05

(C) 2007 guidod
This is a step-by-step description howto turn your own configure check into an autoconf macro - this text tells about the ways to polish the script into a shiny piece that you will really feel like showing them on the Macro Archive.

We suppose you have written a small check already used in your "configure" script - which is actually a bourne shell script that calls other tools and possibly sets an AC_SUBST variable to be replaced in your Makefile.in. It may look like the following check for a "gnu make" in the build environment:

   make_command=""
   for a in "$MAKE" make gmake gnumake 
   do test -z "$a" && continue
      if  ( sh -c "$a --version" 2>/dev/null | grep GNU >/dev/null ) 
      then make_command=$a ; break;
      fi
   done
   if test -z $make_command 
   then ifGNUmake=""
   else ifGNUmake="#"
   fi
   AC_SUBST(ifGNUmake)

In the first step, one would extract that part from the "configure" script and put it into its own file. For a first test, please use the "acinclude.m4" file. The next call of `aclocal && autoconf` will copy the new macro to "aclocal.m4" and from there to "configure". So, now you have an extra file "acinclude.m4" reading:

AC_DEFUN(CHECK_GNU,[
   make_command=""
   for a in "$MAKE" make gmake gnumake 
   do test -z "$a" && continue
      if  ( sh -c "$a --version" 2>/dev/null | grep GNU >/dev/null ) 
      then make_command=$a ; break;
      fi
   done
   if test -n $make_command 
   then ifGNUmake=""
   else ifGNUmake="#"
   fi
   AC_SUBST(ifGNUmake)
])
and in its place in the original "configure.in" you write that name as:
   ....
   CHECK_GNU
   ...

Now you are already done with having your own autoconf macro. And you can be quite sure that it will work in your project - and probably you have tested it on the platforms you do usually build for. Believe it or not, this is a rather "controlled" environment - if you push the macro to the AC Macro Archive then your macro might make it into other projects where they will meet lots of other macros, lots of other shell code, lots of different platforms. And possibly, it will fail over there - however there are some steps that can be checked before.

add m4-quotings - AC_DEFUN([CHECK_GNU])
In the wild, your "CHECK_GNU" might have been already defined elsewhere. It is perfectly possible to redefine a macro but only if AC_DEFUN will see the name. Without the m4-quotes "[...]" however, the predefined macro CHECK_GNU will be expandend before. In many many cases it results in "syntax errors" occuring near your usage of CHECK_GNU and they are not telling about a redefine problem at all. It is really hard to get after that one.
add m4-quotings - AC_SUBST([ifGNUmake])
For the same reason, you should put m4-quotes in any other places where actually an m4-macro is being created - or possibly you are going to use a symbol that might be a complex macro. As a rule of thumb, all uppercase-symbols might be defined as a macro somewhere else. Please put all of them into m4-quotes "[...]". By the way, if you need a pair of "[..]" to be output to the "configure" script, just double (or triple) them as "[[...]]".
var-settings need doublequotes - make_command="$a"
Most people forget about a problem here - if there is a single space between the "=" and anything to follow then the righthand side will be executed as a command and the return value of that command gets assigned. In other words, 'a="echo foo" ; var= $a' will not set "$var" to "foo" but instead print "foo" to the user screen. Putting doublequotes around the righthand side will ensure it gets never ever executed errornously. If you really want to get the execution value, then use backticks to express just that: 'a=`echo foo`'.
test emptyness as : test "x$var" = "x"
The "test" command happens to be implemented very very differently on the various platforms, in fact it is mostly a builtin to the shell you happen to have your configure script get executed with. While "-z" is seen often, even "-n" is rarely implemented. Even more, there are some buggy shells which remove an empty "" string completely instead of providing an empty argument to the "test" command, so that "test" would see a 'test "$var" = ""' as a real 'test =' - and ask for a syntax error.
use cache variables - _cv_make_command
Your macro might be used by other macros which get each expanded into the final "configure" script. That will make your check code to be executed multiple times. Not necessary, and for a compile-and-run test it would be very time consuming. Also, the cache-variables allow a packager guru to pre-set the check-result, yielding faster "configure" and allows to handle problems with cross-compile setups. The configure script will automatically save-to-cache all shell variables containing a "_cv_" in the name.
use AC_MSG_RESULT - after AC_MSG_CHECKING / AC_CACHE_CHECK
Inform the user when the "configure" script enters your macro and when it leaves your macro. If there are problems, they can be identified faster - remember that an extra autoconf macro file is in a distant place perhaps and the original "configure.ac" has only a macro name, and possibly not even your macro name but a different one that happens to use your macro in its definition. At best, inform the user of the result - and try to avoid terminology that is not helpful to a non-coder.
don't be afraid of long names - use AS_VAR_PUSHDEF / POPDEF
You should avoid to destroy shell variable values possibly used somewhere else - or the ones of the other macro calling your macro. As for short-lived variables that do not span over other macros, just use very short names - for the other ones use a long prefix that resembles the name of your macro check.
use a specific prefix - do not use AC_ or AM_
Many macro names might be defined under the same name elsewhere. Usually, you would use a project prefix to avoid double defines, i.e. MYPROJECT_CHECK_GNU. Do never use AC_CHECK_GNU since all AC_ names are reserved - even if you know there is no such macro in the "autoconf" package then it might still be added later. If you intend to submit your macro the AC Macro Archive then you can use the AX_ prefix - we take all macros and we will ensure all macros in the archive are unique. Always and forever.

After applying all these guideline, the macro might now look like this:

AC_DEFUN([AX_CHECK_GNU_MAKE],[
   AC_CACHE_CHECK([for GNU make],ax_cv_gnu_make_command,[
   AS_VAR_PUSHEDEF([_make_command],ax_cv_gnu_make_command)dnl
   _make_command=""
   for a in "$MAKE" make gmake gnumake 
   do test "x$a" = "x" && continue
      if  ( sh -c "$a --version" 2>/dev/null | grep GNU >/dev/null ) 
      then _make_command="$a" ; break;
      fi
   done
   if test "x$_make_command" != "x"
   then ifGNUmake=""
        AC_MSG_RESULT([$_make_command])
   else ifGNUmake="#"
        AC_MSG_RESULT([nothing found])
   fi
   AC_SUBST([ifGNUmake])
   AS_VAR_POPDEF([_make_command])dnl
]])

Now the macro is clean - just add a description block as required in the contribution format and send it to ac-archive-maintainers@gnu.org

However, we can even get to the next level of autoconf macro coding.

add ACTION-IF-TRUE / ACTION-IF-FALSE
If you have a look around then you will notice that most "CHECK" macros have additional and optional arguments. Those may contain shell-code (or other autoconf macros) that should be executed when the autodection fails (or additionally when it succeeds). Autoconf macros are numbered, and the first argument is generally reserved for sub-specifications - e.g. additional "make" program names to check for
dnl AX_CHECK_GNU_MAKE([make names],[ACTION-IF-FOUND],[ACTION-IF-NOT])
AC_DEFUN([AX_CHECK_GNU_MAKE],[
   AC_CACHE_CHECK([for GNU make],ax_cv_gnu_make_command,[
   AS_VAR_PUSHEDEF([_make_command],ax_cv_gnu_make_command)dnl
   _make_command=""
   for a in "$MAKE" $1 make gmake gnumake 
   do test "x$a" = "x" && continue
      if  ( sh -c "$a --version" 2>/dev/null | grep GNU >/dev/null ) 
      then _make_command="$a" ; break;
      fi
   done
   if test "x$_make_command" != "x"
   then ifGNUmake=""
        AC_MSG_RESULT([$_make_command])
        $2
   else ifGNUmake="#"
        AC_MSG_RESULT([nothing found])
        $3
   fi
   AC_SUBST([ifGNUmake])
   AS_VAR_POPDEF([_make_command])
]])
use sugar - either m4sugar or m4sh sugar
The m4 macro processor has lots of ways to avoid that parts get pushed into the final "configure" script unessarily or in way being unportable. Have a look at /usr/share/autoconf/m4sugar/m4sugar.m4 and /usr/share/autoconf/m4sugar/m4sh.m4

Among the possible usages - one can avoid the extra space in the example if there are no optional $2 or $3 argument. We use the m4sugar m4_ifvaln for that, i.e.

   then ifGNUmake=""
        AC_MSG_RESULT([$_make_command])
        m4_ifvaln([$2],[$2])dnl
   else ifGNUmake="#"
        AC_MSG_RESULT([nothing found])
        m4_ifvaln([$3],[$3])dnl
   fi

In this example it would only be one line saved - but one can save a lot more in other places. Let's consider the case that the check-value is only used to execute an ACTION whereas both action-defs are optional as arguments. The shell does have a default "no-operation" statement named ":", so the first attempt might read as

   if test "x$testvalue" = "xyes" 
   then $2
        :
   else $3
        :
   fi

That one is simply needed since the shell might call for a "syntax error" if there is nothing after "then" and before "else". And in fact, the $2 and $3 ACTION might be empty. A more interesting approach would be to use some m4sugar as

   if test "x$testvalue" = "xyes" ; then
        m4_ifvaln([$2],[$2],[:])dnl
        m4_ifvaln([$3],[else $3])dnl
   fi