how to set include paths with autotools

Matei David picture Matei David · Nov 27, 2013 · Viewed 30.8k times · Source

I'm working on a C++ project that uses autoconf & automake, and I'm struggling to correctly set up the include paths in *CPPFLAGS. I've read about 3 hours worth of documents, and I can't figure it out yet. I'm not looking for a hack, but for the correct way to do this. Here is my conundrum.

As I see it, there are 3 completely different sources for include paths:

  1. External libraries that must be installed along with my package, which are configured by configure --with-XXX=<PATH>.
  2. Within my package, some source files use #include <file.h> even when file.h is part of the package, so to compile them, I must set the include path correctly. (Note, it's not an option to edit all these files.)
  3. Whimsical (or not) standards specify the user must be allowed to specify their own (extra) include paths. That is, I shouldn't be setting CPPFLAGS at all.

In my current setup:

  • Type 1 paths are set inside configure.ac by AC_SUBST(CPPFLAGS, "$CPPFLAGS -I<path>").
  • Type 2 paths are set inside Makefile.am by test_CPPFLAGS = -I<path>.
  • Type 3 cannot be set. More exactly, if the user sets CPPFLAGS before running make, this overrides Type 1 settings, causing compilation to fail. Of course, the user could try to use CXXFLAGS instead, but that one has a different use (remember, I'm asking for the correct way to do this, not a hack).

I tried to fix this by setting Type 1 paths using AM_CPPFLAGS inside configure.ac. (For reference: if you set AM_CPPFLAGS instead of CPPFLAGS, but you still need to run some checks such as AC_CHECK_HEADERS, you need to temporarily set CPPFLAGS and then revert it for the checks to work; this is explained here.) This frees up CPPFLAGS for Type 3 paths, but unfortunately the compilation fails because the Makefile-s that gets produced by configure will only use AM_CPPFLAGS if no specialized <target>_CPPFLAGS exists. So, if test_CPPFLAGS exists with a Type 2 path, compiling test will fail because it doesn't get the Type 1 path.

A fix would be to specify inside Makefile.am to always use AM_CPPFLAGS. But is this "by the book"? Can I do this in a global way, or do I have to edit every single target_CPPFLAGS? Is there another "correct" solution?

Answer

Brett Hale picture Brett Hale · Nov 27, 2013

I know it's difficult to get a straight answer from the autotools manuals. There are a couple of good start-to-finish tutorials here and here.

There isn't a standard variable for package-specific *CPPFLAGS in autoconf. configure can be invoked with CPPFLAGS=..., and automake will add this CPPFLAGS to the relevant makefile rules - search for CPPFLAGS in a Makefile.in file for examples. For that reason, I suggest that you not use this variable for anything else.

Add flags in Makefile.am to the AM_CPPFLAGS variable (the default for all preprocessor calls) or override individual preprocessor flags with target_CPPFLAGS. In the example of a 3rd party library, it's best to use a name like: FOO_CPPFLAGS to hold preprocessor options, e.g.,

FOO_CPPFLAGS="-I${FOO_DIR}/include -DFOO_BAR=1"
...
AC_SUBST(FOO_CPPFLAGS)

and in the Makefile.am :

AM_CPPFLAGS = -I$(top_srcdir) $(FOO_CPPFLAGS)
# or:
target_CPPFLAGS = -I$(top_srcdir) $(FOO_CPPFLAGS)

The top_srcdir variable is defined by configure - I use it to illustrate the 2nd case. Let's say you have file.h in another directory other, under the top-level directory. -I$(top_srcdir) allows you to include it as <other/file.h>. Alternatively, -I$(top_srcdir)/other would allow you to include it as <file.h>.

Another useful preset variable is srcdir - the current directory. -I$(srcdir) is added to AM_CPPFLAGS by default. So if file.h is in the current directory you can include it with <file.h> or even "file.h". If other was a 'sibling' directory, -I$(srcdir)/.. would allow you to include <other/file.h>, and -I$(srcdir)/../other would allow <file.h>.


I'd also add that some packages install a pkg-config .pc file. Provided the installation of pkg-config is set up to search the right directories, you might find the PKG_CHECK_MODULES macro very useful.