how to set include paths with autotools

autoconf, automake, autotools, include-path

Solution

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.

Problem

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: - External libraries that must be installed along with my package, which are configured by `configure --with-XXX=<PATH>`. - 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.) - 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?

Original source