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 | 

Reply via email to