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 |