Firstly, apologies for the cross-posting, particularly giving the fact that I am including code, but this message contains issues relevant to both automake and autoconf. For a while I have been thinking that it would be nice to be able to support "include" in autoconf/automake Makefiles. This would be particularly nice with automake which generates very large repetitious Makefiles. Currently there are three ways to do inclusion that I can think of (AC_SUBST_FILE, the Makefile:include.mk hack and automake's include) but all these result in full expansion of the included file in the final Makefile. I am talking about a real include that is done by Make and not by auto{conf|make}. A big motivation for me, is to use this with automake. I have at least one project which has a large number of Makefiles and uses a single include file to add extra rules. The big problem with the current setup is a single change to the include file means rerunning automake/config.status on _every_ Makefile. Using an include mechanism it should be possible to just regenerate the include file and have everything worked out. The problem is of course, that not all makes do include the same way. There are basically two flavours. #SYSV and GNU make include file #BSD make (although most of the later BSD makes seem to support include) .include "file" And while I cannot actually find a version of make that doesn't support include in some form, for safety we probably want to support some sort of hack that does an inline expansion of the include file if there is no Make support. To this end I have hacked up some autoconf macro's that do a check to see if include is supported and emulate it if it isn't. You use it this way: In your Makefile do: #Lots of lovely make rules ... @INCLUDE@ @INCLUDE_QUOT@@top_srcdir@/include.mk@INCLUDE_QUOT@ (Yes I know the syntax is ugly and hard to read, but it is the easiest way to do it without having to dig through autoconf internals). Then in your configure.ac do: AC_CONFIG_MAKEFILES(include.mk Makefile) Which automatically calls AC_PROG_MAKE_INCLUDE to check for include support (if it hasn't already been called). I have a reasonable amount of comments in the code, so it should be easy enough to follow, and it seems to work on all the systems I have access to. I have tried to avoid using autoconf internals wherever possible. It is a hack and a bit fragile in places, but as a proof of concept it is probably a good start. Better support would probably require some access to automake internals. For example, you would tend to want to have a single include.mk with all the VAR=@VAR@ stuff and include this from all the other Makefiles so it makes sense to have the @INCLUDE@ subsitution very close to the top of the sed commands list to avoid having to run through all the other substitutions. This would speed up config.status for a lot of files. This might also make it easier to address the problem of recursive Makefiles in automake by doing the following: Generate top level include with all the common stuff. Generate directory specific stuff in a per-directory include file Generate directory specific Makefile including top-level and per-directory include Generate top-level Makefile with directory specific and all the per-directory files included. This allows you to still do "cd foo; make" when that make sense. Of course resolving the namespace issues here would be non-trivial. Any comments, suggestions?
# AC_PROG_MAKE_INCLUDE # -------------------- # See if the version of make we are using supports include. This macro # runs make trying include and then .include to see if make supports including # in this way. It substitutes the variables @INCLUDE@ and @INCLUDE_QUOT@ # in the output file. If make does not support either include or .include # Then @INCLUDE@ is set to %INCLUDE% and the AC_CONFIG_MAKEFILES macro emulates # the include. This macro is automatically called by AC_CONFIG_MAKEFILES if # has not already been run. AC_DEFUN([AC_PROG_MAKE_INCLUDE], [#Check how make supports include ac_make_var=$MAKE; if test "x$ac_make_var" = x ; then ac_make_var=make; fi set dummy $ac_make_var; ac_make=`echo "$[2]" | sed 'y,./+-,__p_,'` AC_CACHE_CHECK([how $ac_make_var supports include],dnl ac_cv_prog_make_${ac_make}_inc, [#Create file to include cat >conftestmakeinc <<\EOF all: @echo 'ac_maketemp=$(ac_make_inc)' EOF #Set defaults which are used if this macro cannot find a method to do #Makefile includes ac_try_quot='"' eval "ac_cv_prog_make_${ac_make}_inc_quot='$ac_try_quot'" eval ac_cv_prog_make_${ac_make}_inc=none #Try to discover how to do a Makefile include. We try "include" first as this #is supported by the widest range of Makes (SYSV, GNU Make and some versions #of BSD Make with SYSV support) for ac_try_make_inc in include .include ; do case $ac_try_make_inc in .include) #BSD style make, we need to quote the argument ac_try_quot='"';; include) #SYS V style make don't quote the argument ac_try_quot=;; esac #Create test Makefile with the candidate include method cat > conftestmake <<EOF ac_make_inc=$ac_try_make_inc $ac_try_make_inc ${ac_try_quot}conftestmakeinc${ac_try_quot} EOF #See if it worked eval `$ac_make_var -f conftestmake 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_inc_quot='$ac_try_quot' eval ac_cv_prog_make_${ac_make}_inc=$ac_maketemp break fi done rm -f conftestmake rm -f conftestmakeinc])dnl eval ac_maketemp="`echo '$ac_cv_prog_make_'${ac_make}_inc`" eval ac_makequot="`echo '$ac_cv_prog_make_'${ac_make}_inc_quot`" #If our make has no support for include then we will need #to emulate it. This is done by a sed script in AC_CONFIG_MAKEFILES INCLUDE_PATTERN="# -- Included automatically by configure from" if test x$ac_maketemp = xnone ; then INCLUDE="$INCLUDE_PATTERN" ac_emulate_make_inc=1 else INCLUDE=$ac_maketemp fi INCLUDE_QUOT=$ac_makequot dnl Do substituitions AC_SUBST(INCLUDE) AC_SUBST(INCLUDE_QUOT) ]) #AC_PROG_MAKE_INCLUDE # AC_CONFIG_MAKEFILES(FILES,[CMDS],[INIT-CMDS]) # -------------------------------------------- # Output Makefiles. If make does not support a mechanism for including other # makefiles, this macro will emulate it. This should be used in the # following way: # # In the Makefile.in: # # @INCLUDE@ @INCLUDE_QUOT@file/to/include.mk@INCLUDE_QUOT@ # # In ./configure.ac: # # AC_CONFIG_MAKEFILES(file/to/include.mk Makefile) # # The following limitations apply to the use of @INCLUDE@ in Makefiles. # # 1. The file must not include any Make variables (i.e. $(var)) as these will # not be expanded if include is being emulated. You may however, use any # variables substituted by configure (i.e. @var@). # # 2. @INCLUDE@ should start in the first column of the file, with no leading # space or tabs. # # 3. The string "# -- Included automatically by configure from" should not # appear anywhere in your Makefile. # # 4. Included files may include other files. However, if include emulation # is being used order is important in AC_CONFIG_MAKEFILES. You need to # specify the files in the order: includedbyx x yincludesx. In addition, # when running ./config.status to generate a single Makefile # that has changed, you should also update all files that depend on this # Makefile. A way to do this is to add a dependency list to the Makefile # itself. # # CMDS, and INIT-CMDS work the same way as they do for AC_CONFIG_FILES, but # are run before any include substitutions are done. # # Note: This code makes aomw assumptions about some internals of autoconf. # # 1. That the current Makefile being substituted is in the variable $ac_file. # 2. That the variable $as_me contains the basename of the config.status # script. # 3. $tmp is a valid temporary directory that has been created # 4. The variable CONFIG_COMMANDS lists any command tags to be run # AC_DEFUN([AC_CONFIG_MAKEFILES], [ AC_REQUIRE([AC_PROG_MAKE_INCLUDE]) AC_CONFIG_FILES([$1], [CONFIG_MAKEFILES="$CONFIG_MAKEFILES $ac_file"] [$2], CONFIG_COMMANDS="$CONFIG_COMMANDS emulate-make-include" [$3]) AC_CONFIG_COMMANDS(emulate-make-include, [#Emulate include in Makefiles if needed if test "x$ac_emulate_make_inc" != "x" && test "x$ac_emulate_make_run" = "x" then for ac_file in $CONFIG_MAKEFILES ; do echo $as_me: emulating make include for $ac_file >&2 changequote(, )dnl dir=`expr "x$ac_file" : 'x\(.*\)/[^/]*' \| . : '\(.\)'` basename=`expr //$ac_file : '.*/\(.*\)'` (cd $dir; # The following extracts lines with the include pattern from a Makefile # and uses the information in them to generate a sed script to do the # actual substitution # # Note: the regular expression in the following sed statement replaces # occurances of $INCLUDE "path" with a new sed command to include # "path" in the target Makefile. Because '/' often appears in # pathnames \|RE| is used to do address matching instead of /RE/ # # Note: that the [ ] below contains a space and a literal tab grep "$INCLUDE" $basename | sort -u | \ sed 's:\('"$INCLUDE"'[ ]\{1,\}\)"\(.*\)".*$:\\|\1"\2".*$|r \2:' \ > $tmp/makeincludes.sed changequote([, ])dnl #Should really break up this script, but we are unlikely to #exceed the max number of lines we are allowed in a sed sed -f $tmp/makeincludes.sed < $basename > $tmp/$basename.tmp mv $tmp/$basename.tmp $basename rm -f $tmp/makeincludes.sed ) done #Protect against multiple executions, otherwise files will get included into #the Makefile more than once ac_emulate_make_run=1 fi], [INCLUDE="$INCLUDE"; ac_emulate_make_inc="$ac_emulate_make_inc"]) ]) # AC_CONFIG_MAKEFILES