autotoolsautoconfautomake

Makefile.am: How to list all files (of specific extension) in `foo_HEADERS`?


In a Makefile.am, there is the following rule that mentions all *.h files in that specific folder (several hundreds of them):

foo_HEADERS = file1.h file2.h ...

As the project evolves, new header files are being added to that folder, and I am looking for a method that picks up all .h files automatically. What doesn't work is to use Makefile stuff like $(wildcard).

Respective Makefile is one of the AC_CONFIG_FILES in configure.ac so I came up with the following:

In Makefile.am:

foo_HEADERS = @FOO_INCLUDE_HFILES@

EXTRA_HEADERS =

In configure.ac:

Add AC_SUBST for FOO_INCLUDE_HFILES:

# Build a list of all .h files in  $(srcdir)/include/foo  as using
# make variables like $(wildcard) won't pan out as desired.
ac_include_foo_h_files=`ls $srcdir/include/foo/*.h`
ac_include_foo_h_files=`basename -a $ac_include_foo_h_files`
AC_SUBST(FOO_INCLUDE_HFILES, "`echo $ac_include_foo_h_files`")

Question:

My solution works as expected, but I am unsure w.r.t. it's generic enought to work in all OSes supported by autotools.

  1. Is there a better, more generic approach, in particular for explicit ls .../*.h and basename -a ... and echoA)?

  2. In case my approach is the way to go, why must EXTRA_HEADERS be setB) in Makefile.am?


A) The echo is needed to get rid of newlines in ac_include_foo_h_files.

B) Otherwise I am getting an error.


Solution

  • In a Makefile.am, there is the following rule that mentions all *.h files in that specific folder (several hundreds of them):

    foo_HEADERS = file1.h file2.h ...
    

    As the project evolves, new header files are being added to that folder, and I am looking for a method that picks up all .h files automatically.

    The canonical and most appropriate way to do this is to list all the files explicitly. There being hundreds of them is unusual and says something (I don't know what) about the project, but does not change the fact. It ought to be the build system that is authoritative for what gets built and (in this case) installed. Automake does not define any other supported way. And it's not that hard.

    Respective Makefile.am is one of the AC_CONFIG_FILES in configure.ac

    Are you sure? The corresponding Makefile should be in AC_CONFIG_FILES, but not Makefile.am (nor Makefile.in). Supposing that you meant it is the Makefile that is listed in AC_CONFIG_FILES, this in Makefile.am ...

    foo_HEADERS = @FOO_INCLUDE_HFILES@
    
    EXTRA_HEADERS =
    

    ... is relying on Automake to pass the @FOO_INCLUDE_HFILES@ through to the Makefile.in that it generates, where it will be meaningful to configure. This also assumes that Automake does not rely on any of its own analysis of the variable's value, which I think is true but cannot confirm.

    Add AC_SUBST for FOO_INCLUDE_HFILES:

    # Build a list of all .h files in  $(srcdir)/include/foo  as using
    # make variables like $(wildcard) won't pan out as desired.
    ac_include_foo_h_files=`ls $srcdir/include/foo/*.h`
    ac_include_foo_h_files=`basename -a $ac_include_foo_h_files`
    AC_SUBST(FOO_INCLUDE_HFILES, "`echo $ac_include_foo_h_files`")
    

    If you want to hack on configure.ac then you really ought to get a better grasp on shell programming. Use modern $() instead of `` for command substitution. Do not interpose ls where your glob by itself already provides the file list you want. And expanding a variable as an argument to echo, just to (re-)capture that? You have newlines in the variable's value only because you are unwisely capturing the output of ls in the first place, but even having done that, the echo trick is a weird way to solve the problem.

    Also $(srcdir) is a command substitution, which will probably fail. You seem to want a parameter expansion instead. And POSIX basename does not document any option arguments, just filenames.

    And do not create or use your own variables with the ac_ name prefix. Autoconf reserves that prefix for its own internal use.

    Is there a better, more generic approach, in particular for explicit ls .../*.h and basename -a ... and echo?

    If I were writing that (though I wouldn't; see above), it might look more like this:

    FOO_INCLUDE_HFILES=
    for header in "${srcdir}"/include/foo/*.h; do
      FOO_INCLUDE_HFILES="${FOO_INCLUDE_HFILES} ${header##*/}"
    done
    
    # Mark FOO_INCLUDE_HFILES as an output variable
    AC_SUBST([FOO_INCLUDE_HFILES])
    

    That assumes only features of the POSIX shell, btw; if I were writing for Bash then I'd probably use an array instead of a loop, and I might use pushd / popd to avoid the need for basename.

    In case my approach is the way to go, why must EXTRA_HEADERS be set in Makefile.am?

    Your approach is not the way to go. It does not conform to Automake's documented requirements, as already discussed. I can't explain exactly why it makes a difference to define an empty EXTRA_HEADERS variable in this case, but I take it as a result of your misuse of Automake.