I've written a macro which makes it easier to write more flexible autoconf-macros, and I thought some of you might find it interesting. It's in the public domain so do whatever you want with it (except pornographic stuff - I won't have any of that... ;) I've called it SIM_PARSE_MODIFIER_LIST() and it handles parsing of modifier-list arguments. A modifier-list is an optional argument that can contain keywords (modifiers) that will change the behaviour of your macro. All parsing is done on the m4-level, so most problems will be caught at m4-run-time (while running e.g. aclocal and autoconf) instead of while running configure. Error messages are printed for a lot of error-cases. The macro sets up a set of defines with default values, and then a set of modifiers and how they change the previously given defines. Let's say you're writing a macro: AC_my_TEST( arg1, arg2, opt MODIFIERS ) AC_DEFUN([AC_my_TEST],[dnl SIM_PARSE_MODIFIER_LIST([$3],[ m4_my_debug_setting false m4_my_default_setting true ],[ debug m4_my_debug_setting true nodebug m4_my_debug_setting false default m4_my_default_setting true nodefault m4_my_default_setting false ]) After having invoked this macro, you now have the two defines "m4_my_debug_setting" (default value false) and "m4_my_default_setting" (default value true) which you can test the value of, both on the m4-level and at the shell level, like for instance this: ifelse(m4_my_debug_setting, true, [errprint([problem right here! ]), []) or if test x"m4_my_debug_setting" = "xtrue"; then AC_MSG_ERROR([macro was set up incorrectly]) fi Having the define set on the m4-level gives the advantage that you can get the value of it into e.g. the AC_ARG_WITH() help-text. A shell-variable won't be set up at the time the help-text is displayed, so the macro setting can't affect the help-text. You can also catch problems already at m4-run-time. Now, over to your configure.in, you would now be able to invoke your macro like this: AC_my_TEST([arg1], [arg2]) => default values will be used AC_my_TEST([arg1], [arg2], nodefault) => m4_my_default_setting will be false during macro invocation. AC_my_TEST([arg1], [arg2], nodeflllt debug) error=> SIM_PARSE_MODIFIER_LIST: modifier(s) parse error: "nodeflllt" (settings will be configured for the macro invocation for the modifiers that are parsed correctly - m4_my_debug_setting will be true) You get the drift... I find this macro useful, and I hope you will too. It would of course be even more useful as a standard part of autoconf so you won't have to install the modifierlist.m4 fiel together with the macros that use it :( Any comments? [attachment 1: modifierlist.m4 (the macro itself)] [attachment 2: simage.m4 (sample usage og macro)] Lars J
dnl ************************************************************************ dnl Usage: dnl SIM_PARSE_MODIFIER_LIST( MODIFIER-LIST-STRING, MODIFIER-VARIABLES, dnl MODIFIER-LIST, opt ACTION-ON-SUCCESS, opt ACTION-ON-FAILURE ) dnl dnl Description: dnl This macro makes it easy to let macros have a MODIFIER-LIST argument dnl which makes the macro more flexible and lets the macro caller configure dnl some of the macro beaviour from the calling place. dnl dnl Everything is done on the m4-level, which means things are handled at dnl autoconf-run-time, not configure-run-time. This lets you discover dnl problems at an earlier stage, which is nice. It also lets you insert dnl the modifier values into e.g. the help strings, something you can't dnl do with a shell variable. dnl dnl MODIFIER-LIST-STRING is the string of modifiers used in the dnl macro invocation. dnl dnl MODIFIER-VARIABLES is a list of variables and their default values. dnl The variables and values are recognized as words matching [[^\s-]*] dnl separated by whitespace, and they must of course come in pairs. dnl dnl MODIFIER-LIST is a description-list of all the valid modifiers that dnl can be used in the MODIFIER-LIST-STRING argument. They must come in dnl tuples of three and three words (same word-definition as above) where dnl the first word is the modifier, the second word is the variable dnl that is to be set by the modifier, and last the value the modifier dnl variable should be set to. dnl dnl ACTION-ON-SUCCESS is the expansion of the macro if all the modifiers dnl in MODIFIER-LIST-STRING pass through without problem. The default dnl expansion is nothing. dnl dnl ACTION-ON-FAILURE is the expansion of the macro if some of the dnl modifiers in MODIFIER-LIST-STRING doesn't pass through. The default dnl expansion is nothing, but warnings are printed to stderr on the dnl modifiers causing the problem. dnl dnl Sample Usage: dnl [to come later] dnl dnl Authors: dnl Lars J. Aas <[EMAIL PROTECTED]> dnl dnl TODO: dnl * [larsa:20000222] warn on creating modifiers for unknown variables dnl define([$IM_STRING_COMPACT],[dnl patsubst(patsubst([$1],[[ ]+],[ ]),[^ \| $],[])]) define([$IM_STRING_WORDCOUNT_COMPACT],[dnl builtin([eval],(1+len(patsubst([$1],[[^ ]+],[_])))/2)]) define([$IM_STRING_WORDCOUNT],[dnl indir([$IM_STRING_WORDCOUNT_COMPACT],indir([$IM_STRING_COMPACT],[$1]))]) define([$IM_DEFINE_VARIABLE],[dnl dnl errprint([define( $1, $2 ) dnl ])dnl define([$1],[$2]) ]) define([$IM_DEFINE_VARIABLES],[dnl ifelse(indir([$IM_STRING_WORDCOUNT_COMPACT],[$1]), 2, [patsubst([$1],[^\([^ ]+\) \([^ ]+\)], [indir([$IM_DEFINE_VARIABLE],[\1],[\2])])], [patsubst([$1],[^\([^ ]+\) \([^ ]+\) \(.*\)], [indir([$IM_DEFINE_VARIABLE],[\1],[\2])indir([$IM_DEFINE_VARIABLES],[\3])])])dnl ]) define([$IM_PUSHDEF_MODIFIER],[dnl dnl errprint([modifier( $1, $2, $3 ) dnl ])dnl ifelse(defn([$2]), [], [errprint([SIM_PARSE_MODIFIER_LIST: invalid variable (arg 3): "$2" ])], [pushdef([$1],[define([$2],[$3])])])dnl ]) dnl [pushdef([$1],[define([$2],[$3])])] define([$IM_PUSHDEF_MODIFIERS],[dnl ifelse(indir([$IM_STRING_WORDCOUNT_COMPACT],[$1]), 3, [patsubst([$1],[^\([^ ]+\) \([^ ]+\) \([^ ]+\)], [indir([$IM_PUSHDEF_MODIFIER],[\1],[\2],[\3])])], [patsubst([$1],[^\([^ ]+\) \([^ ]+\) \([^ ]+\) \(.*\)], [indir([$IM_PUSHDEF_MODIFIER],[\1],[\2],[\3])indir([$IM_PUSHDEF_MODIFIERS],[\4])])dnl ])dnl ]) define([$IM_POPDEF_MODIFIER],[dnl dnl errprint([popdef( $1 ) dnl ])rnl popdef([$1])dnl ]) define([$IM_POPDEF_MODIFIERS],[dnl ifelse(indir([$IM_STRING_WORDCOUNT_COMPACT],[$1]), 3, [patsubst([$1],[^\([^ ]+\) \([^ ]+\) \([^ ]+\)], [indir([$IM_POPDEF_MODIFIER],[\1])])], [patsubst([$1],[^\([^ ]+\) \([^ ]+\) \([^ ]+\) \(.*\)], [indir([$IM_POPDEF_MODIFIER],[\1])indir([$IM_POPDEF_MODIFIERS],[\4])])])dnl ]) define([$IM_PARSE_MODIFIER_LIST],[dnl pushdef([wordcount],builtin([eval],(indir([$IM_STRING_WORDCOUNT],[$2]))))dnl ifelse(builtin([eval], (wordcount % 2) == 0 && wordcount > 0), 1, [], [errprint([SIM_PARSE_MODIFIER_LIST: invalid word count (arg 2): "]indir([$IM_STRING_COMPACT],[$2])[" ])])dnl popdef([wordcount])dnl indir([$IM_DEFINE_VARIABLES],[$2])dnl pushdef([wordcount],builtin([eval],(indir([$IM_STRING_WORDCOUNT],[$3]))))dnl ifelse(builtin([eval], (wordcount % 3) == 0 && wordcount > 0), 1, [], [errprint([SIM_PARSE_MODIFIER_LIST: invalid word count (arg 3): "$3" ])])dnl popdef([wordcount])dnl indir([$IM_PUSHDEF_MODIFIERS],[$3])dnl ifelse(indir([$IM_STRING_COMPACT],[$1]), [], [ifelse($4, , , $4)], [ifelse($5, , [errprint([SIM_PARSE_MODIFIER_LIST: modifier(s) parse error: ]"indir([$IM_STRING_COMPACT],[$1])"[ ])], $5)])dnl indir([$IM_POPDEF_MODIFIERS],[$3])dnl ]) AC_DEFUN([SIM_PARSE_MODIFIER_LIST],[dnl indir([$IM_PARSE_MODIFIER_LIST], indir([$IM_STRING_COMPACT],[$1]), indir([$IM_STRING_COMPACT],[$2]), indir([$IM_STRING_COMPACT],[$3]), [$4], [$5])dnl ])
dnl ************************************************************************ dnl Usage: dnl SIM_CHECK_SIMAGE( ACTION-IF-FOUND, ACTION-IF-NOT-FOUND, ATTRIBUTE-LIST ) dnl dnl Description: dnl This macro locates the simage development system. If it is found, the dnl set of variables listed below are set up as described and made available dnl to the configure script. dnl dnl ATTRIBUTE-LIST Options: dnl [no]default whether --with-simage is default or not dnl (default on) dnl [no]searchprefix whether $exec_prefix is to be searched dnl (default off) dnl dnl Autoconf Variables: dnl $sim_ac_simage_avail yes | no dnl $sim_ac_simage_cppflags (extra flags the compiler needs for simage) dnl $sim_ac_simage_ldflags (extra flags the linker needs for simage) dnl $sim_ac_simage_libs (link libraries the linker needs for simage) dnl $CPPFLAGS $CPPFLAGS $sim_ac_simage_cppflags dnl $LDFLAGS $LDFLAGS $sim_ac_simage_ldflags dnl $LIBS $sim_ac_simage_libs $LIBS dnl dnl Automake Conditionals: dnl HAVE_LIBSIMAGE (code disabled) dnl dnl Config.h Defines: dnl HAVE_LIBSIMAGE (code disabled) dnl HAVE_SIMAGE_H (code disabled) dnl dnl Authors: dnl Morten Eriksen, <[EMAIL PROTECTED]> dnl Lars J. Aas, <[EMAIL PROTECTED]> dnl dnl TODO: dnl * [mortene:20000122] make sure this work on MSWin (with Cygwin) dnl * [larsa:20000220] find a less strict AC_PREREQ setting dnl AC_DEFUN(SIM_CHECK_SIMAGE,[ dnl Autoconf is a developer tool, so don't bother to support older versions. AC_PREREQ([2.14.1]) SIM_PARSE_MODIFIER_LIST([$3],[ sim4_simage_with yes sim4_simage_searchprefix no ],[ default sim4_simage_with yes nodefault sim4_simage_with no searchprefix sim4_simage_searchprefix yes nosearchprefix sim4_simage_searchprefix no ]) AC_ARG_WITH(simage, AC_HELP_STRING([--with-simage=DIR], changequote({,}){use simage for loading texture files [default=}sim4_simage_with{]}changequote([,])), , [with_simage=sim4_simage_with]) sim_ac_simage_avail=no if test "x$with_simage" != "xno"; then sim_ac_path=$PATH if test "x$with_simage" != "xyes"; then sim_ac_path=${with_simage}/bin:$PATH ifelse(sim4_simage_searchprefix, yes, [if test "x$exec_prefix" != "xNONE"; then sim_ac_path=$sim_ac_path:$sim_ac_path/bin fi], :) fi AC_PATH_PROG(sim_ac_conf_cmd, simage-config, false, $sim_ac_path) if test "x$sim_ac_conf_cmd" = "xfalse"; then AC_MSG_WARN(could not find 'simage-config' in $sim_ac_path) fi sim_ac_simage_cppflags=`$sim_ac_conf_cmd --cppflags` sim_ac_simage_ldflags=`$sim_ac_conf_cmd --ldflags` sim_ac_simage_libs=`$sim_ac_conf_cmd --libs` AC_CACHE_CHECK([whether the simage library is available], sim_cv_lib_simage_avail, [ sim_ac_save_cppflags=$CPPFLAGS sim_ac_save_ldflags=$LDFLAGS sim_ac_save_libs=$LIBS CPPFLAGS="$CPPFLAGS $sim_ac_simage_cppflags" LDFLAGS="$LDFLAGS $sim_ac_simage_ldflags" LIBS="$sim_ac_simage_libs $LIBS" AC_TRY_LINK([#include <simage.h>], [(void)simage_read_image(0L, 0L, 0L, 0L);], sim_cv_lib_simage_avail=yes, sim_cv_lib_simage_avail=no) CPPFLAGS=$sim_ac_save_cppflags LDFLAGS=$sim_ac_save_ldflags LIBS=$sim_ac_save_libs ]) if test x"$sim_cv_lib_simage_avail" = xyes; then sim_ac_simage_avail=yes CPPFLAGS="$CPPFLAGS $sim_ac_simage_cppflags" LDFLAGS="$LDFLAGS $sim_ac_simage_ldflags" LIBS="$sim_ac_simage_libs $LIBS" dnl AM_CONDITIONAL(HAVE_LIBSIMAGE, true) dnl AC_DEFINE(HAVE_SIMAGE_H, 1, dnl [Define this if you have simage.h]) dnl AC_DEFINE(HAVE_LIBSIMAGE, 1, dnl [Define this if you are going to use libsimage]) ifelse($1, , :, $1) else dnl AM_CONDITIONAL(HAVE_LIBSIMAGE, false) ifelse($2, , :, $2) fi else ifelse($2, , :, $2) fi ])