Hi all, Ever since reading the hack for working around the problem of how you install autoconf generated config.h files in the GNU Autoconf, Automake, Libtool book, I have thought that there must be a better way to do it. To this end, I have hacked up some macros that allow you to do this a better way. The basic idea is to write a config.h.in template that is then selectively preprocessed to generate a config.h that can be installed. It's not perfect, but it seems to work. The macro header comment gives a pretty good explanation of the motivation, how it works and what the limitations are. I have only given this a limited test wrt to different platforms, but as the majority of this is sed code, and SUN's sed is pretty unforgiving it should be portable. The code also relies on a couple of autoconf internals (AC_LIST_HEADERS, filename to create is $ac_dest) but nothing too scary. I'd appreciate any comments. Cheers.
# AC_CONFIG_HEADERS_INSTALLED(HEADERS, [CMDS], [INIT-CMDS]) # --------------------------------------------------------- # # Create installable header files from templates and preprocessor variables # defined by autoconf. # # In general the 'config.h' header files generated by AC_CONFIG_HEADERS # are not suitable for installation. This is because any autoconf/automake # packages will reuse the same preprocessor macros together causing a clash # when you try to build more than one package. # # AC_CONFIG_HEADERS_INSTALLED works by using the variables defined by # configure to perform selective preprocessing on a header template. The # resulting header file can therefore be installed and included by other # packages. For example: using the following configure.ac file # # AC_INIT # AC_HEADER_SYS_WAIT # AC_HEADER_STDC # AC_CHECK_FUNCS(strchr memcpy) # AC_CONFIG_HEADERS_INSTALLED(config.h) # AC_OUTPUT # # You would create a template (config.h.in) as follows: # # /* Installable config file */ # #include <sys/types.h> # #if HAVE_SYS_WAIT_H # # include <sys/wait.h> # #endif /* HAVE_SYS_WAIT_H */ # # @BEGIN_VERBATIM@ # #ifndef WEXITSTATUS # # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) # #endif /* !WEXITSTATUS */ # #ifndef WIFEXITED # # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) # #endif /* !WEXITED */ # @END_VERBATIM@ # # #if STDC_HEADERS # # include <string.h> # #else /* STDC_HEADERS */ # # if ! HAVE_STRCHR # # define strchr index # # define strrchr rindex # # endif /* ! HAVE_STRCHR */ # char *strchr (), *strrchr (); # # if ! HAVE_MEMCPY # # define memcpy(d, s, n) bcopy ((s), (d), (n)) # # define memmove(d, s, n) bcopy ((s), (d), (n)) # # endif /* ! HAVE_MEMCPY */ # #endif /* STDC_HEADERS */ # # When config.status is executed it performs a selective preprocess of this # template using cpp and preserving all preprocessor directives except # #if, #else and #endif (and friends). In addition, anything between # @BEGIN_VERBATIM@ and @END_VERBATIM@ is output verbatim to the resulting # header file. # # For example, on a system where HAVE_SYS_WAIT_H and STDC_HEADERS are defined # the config.h file would look like: # # /* config.h. Generated automatically by configure */ # /* Installable config file */ # #include <sys/types.h> # # # include <sys/wait.h> # #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif /* !WEXITSTATUS */ #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif /* !WEXITED */ # # include <string.h> # # Note that all comments are preserved in the output. # # AC_CONFIG_HEADERS_INSTALLED will work either with or without one or more # standard autoconf headers as generated using autoheader and # AC_CONFIG_HEADERS. # # Limitations # ----------- # # The selective preprocessor code is not perfect and has the following # _known_ limitations: # # 1. Behavior is undefined when using more than one comment on a line # (e.g. /* comment 1 */ bar /* comment 2 */), so don't. # # 2. The template should not contain any literal strings (i.e. between "s) # containing the pattern "__AUTOCONF_<blah>__" # # 3. Multi-line macros must not end on an empty line, i.e: # #define MY_MACRO(x) \$ # x++ \$ # $ # # Is wrong, but # # #define MY_MACRO \$ # x++ \$ # $ # ^space # # is okay. # # 4. Backslashes are not preserved in the output (except in #defines and in # verbatim sections). # # 5. You might think that it was useful to do the following: # # #define MYVAR PACKAGE /* PACKAGE defined by configure */ # # to rename an autoconfigured macro. You can't. # AC_DEFUN([AC_CONFIG_HEADERS_INSTALLED], [AC_REQUIRE([AC_PROG_CPP]) AC_CONFIG_COMMANDS($1, [# Preprocess installable config header template AC_MSG_NOTICE([creating $ac_dest]) cp $srcdir/$ac_dest.in $tmp/config.h.in changequote(, )dnl #Note in most of this code something that looks like [ ], actually contains #a space and a literal tab #Create sed script to preserve stuff we don't want the preprocessor to touch #We do this by stuffing everything into a string literal. cat>$tmp/confinstinc.sed<<\AHEOF #Preserve verbatim /@BEGIN_VERBATIM@/,/@END_VERBATIM@/ { /@BEGIN_VERBATIM@/ d /@END_VERBATIM@/ d s,\(.*\),__AUTOCONF_VERBATIM__\1__AUTOCONF_VERBATIM__, } /^__AUTOCONF_VERBATIM__.*__AUTOCONF_VERBATIM__/!{ #Remove comments from # directives s,^\([ ]*#.*\)\/\*.*\*\/\(.*\),\1\2,g #Preserve #includes s,^\([ ]*#[ ]*include.*\)$,__AUTOCONF_include__\1__AUTOCONF_include__, #Preserve #defines s,^\([ ]*#[ ]*define.*\)$,__AUTOCONF_define__\1__AUTOCONF_define__, /__AUTOCONF_define__.*\\__AUTOCONF_define__/,/.*[^\\]$/ { /__AUTOCONF_define__.*__AUTOCONF_define__/!s,\(.*\),__AUTOCONF_define__\1__AUTOCONF_define__, } #Preserve #undefs, errors, pragmas and warn s,^\([ ]*#[ ]*undef.*\)$,__AUTOCONF_undef__\1__AUTOCONF_undef__, s,^\([ ]*#[ ]*errors.*\)$,__AUTOCONF_error__\1__AUTOCONF_error__, s,^\([ ]*#[ ]*warn.*\)$,__AUTOCONF_warn__\1__AUTOCONF_warn__, s,^\([ ]*#[ ]*pragma.*\)$,__AUTOCONF_pragma__\1__AUTOCONF_pragma__, #Preserve C++ comments s,//\(.*\),__AUTOCONF_COMCPP__\1__AUTOCONF_COM__, #Preserve one line comments. #Note (we don't cope well with more than one comment on the #same line. (e.g. /* comm */ code /* comm */ so don't do this) s,\/\*\(.*\)\*\/,__AUTOCONF_COMBEG__\1__AUTOCONF_COMEND__, #Preserve Multi-line comments /\/\*/,/\*\// { /\/\*/ s,/\*\(.*\)$,__AUTOCONF_COMBEG__\1__AUTOCONF_COM__, /\*\// s,\(.*\)\*/,__AUTOCONF_COM__\1__AUTOCONF_COMEND__, /__AUTOCONF_COM__/!s,\(.*\),__AUTOCONF_COM__\1__AUTOCONF_COM__, } } #Preserve embedded " /__AUTOCONF_[^_]\{1,\}__/ s,",\\",g #Stringfy all the __AUTOCONF__ stuff so that it is a valid C token s:\(__AUTOCONF_[^_]\{1,\}__.*__AUTOCONF_[^_]\{1,\}__\):"\1":g AHEOF sed -f $tmp/confinstinc.sed < $tmp/config.h.in > $tmp/config.h.in.pre #Using all the previously installable config headers and any DEFS create #the config.h.in using cpp. cat AC_LIST_HEADERS $tmp/config.h.in.pre > $tmp/config.h $CPP $DEFS $tmp/config.h > $tmp/config.h.in.pre #Make sed script to Post-process and tidy up output cat > $tmp/confinstinc.sed << \AHEOF #Remove # line-no "file" directives from the output /[ ]*#[ ]* [0-9]\{1,\} ".*"$/ d #Clean up whitespace /^[ ]*$/,/[^ ]/ { /[^ ]/!d /[^ ]/ i\ } #Fix \" back up /"__AUTOCONF.*/ s,\\",",g #Put back comments s,["]*__AUTOCONF_COMBEG__,/*, s,__AUTOCONF_COMEND__["]*,*/, #Fix up preserved directives s,"__AUTOCONF_\([^_]*\)__,, s,__AUTOCONF_\([^_]*\)__",, AHEOF echo "/* $ac_dest. Generated automatically by configure */" > $tmp/config.h sed -f $tmp/confinstinc.sed < $tmp/config.h.in.pre >> $tmp/config.h changequote([, ]) #Create dir if needed dirname=`AS_DIRNAME([$ac_dest])` if test ! -d $dirname; then AS_MKDIR_P([$dirname]) fi #See if config.h has changed if test -f $ac_dest ; then if cmp -s $ac_dest $tmp/config.h 2>/dev/null; then AC_MSG_NOTICE([$ac_dest is unchanged]) else mv $tmp/config.h $ac_dest fi else mv $tmp/config.h $ac_dest fi ] $2, [CPP="$CPP"; DEFS="$DEFS"] $3) ])# AC_CONFIG_HEADERS_INSTALL
Dean Povey, | e-m: [EMAIL PROTECTED] | JCSI: Java Crypto Toolkit Research Scientist | ph: +61 7 3864 5120 | uPKI: C PKI toolkit for embedded Security Unit, DSTC | fax: +61 7 3864 1282 | systems Brisbane, Australia | www: security.dstc.com |