Search code examples
linuxheader-filesautotools

ensure config.h is included once


I have a library project that I'm working on porting to using the autotools suite in Linux. I'm quite new to autotools (this week). I've learned the basics of its operation. I have a question about how to keep the contents of config.h from being redefined.

I'm surprised to find that the generated config.h file doesn't either, 1) wrap each macro in a #ifndef or, 2) that the entire file isn't wrapped in the standard #ifndef CONFIG_H.

As I've alluded, this code is built on Windows and Linux. Thus there are several uses of a macro, _linux (I'm not saying that's the best name, but it's in use everywhere) to bring in elements to classes which exist in Linux only. Thus, this will happen

header.h

#ifndef HEADER1_H
#define HEADER1_H

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#endif

source.cxx

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "header.h"  // oops, preprocessor gets excited because of redefs

One simple solution is I do that standard unique wrap in config.h.in after the file is generated. However, I was wondering, is there a better way of handling this? I can't be the first to encounter this and there might even be a means of handling it in configure.ac but being a complete neophyte in this, I don't know what to even search for.


Solution

  • The way I do this is indeed creating a wrapper file (which I usually call global.h) that reads like this.

    #ifndef MY_PROJECT_GLOBAL_H
    #define MY_PROJECT_GLOBAL_H
    
    #include <config.h>
    
    /* Maybe other global definitions… */
    
    #endif
    

    Note that the recommended way to #include the config.h file is via <config.h> not "config.h" so it works better with VPATH builds.

    Then, all the source files in my project #include this global.h header as their very first #include and don't care about config.h. A header file should never #include config.h since this would lead to bad name conflicts. Actually, if you stick to this guideline, your code should also work without #include guards in the configuration header.


    Update regarding OP's comment

    Or: How to use configuration results in headers?

    If your headers need to declare different things depending on the results of the configure script, you have a number of options, none of which is perfect.

    For internal headers, there is no problem. They simply rely on the macros being #defined without #includeing anything. This works if – as is recommended – all source files #include (maybe indirectly as shown above) config.h before any other header.

    If the headers are to be installed publicly, this is not such a great solution. For those of your users that use Autoconf, it wouldn't be that bad, although even those would have to remember what checks to place in their configure.ac files. For users who don't use Autoconf, it will be pretty bad. If you only have a few switches (such as Glibc's fature test macros), it is okay to ask your users to #define them before #includeing your headers but if you need many, this is not a real option. Not to mention that you'll expose a lot of implementation details to your users that way.

    If all you need to do is branch depending on the platform you are building for, you could probe some of the pre-defined macros like __linux or _WIN32. There is the Boost.Predef library that aims to make these check a little more convenient by providing a higher-level abstraction. The library works with C and C++ alike but, of course, it adds an additional dependency to your project.

    Finally, you could make a version of your config.h that uses a macro prefix specific to your project. There is a contribution in the Autoconf macro archive that does exactly that for you. A minimal example could look like this.

    AC_PREREQ([2.69])
    AC_INIT([example-project], [1.0], [bugs@example.org])
    AC_CONFIG_SRCDIR([example.c])
    AC_CONFIG_MACRO_DIR([m4])
    AC_CONFIG_HEADERS([config.h])
    AX_PREFIX_CONFIG_H([public_config.h], [EXAMPLE_PROJECT], [config.h])
    AC_PROG_CC
    AC_OUTPUT
    

    Save this as configure.ac, download ax_prefix_config_h.m4 from the Autoconf macro archive and place it in the sub-directory m4 and then run autoreconf && ./configure. It will create the normal config.h and in addition public_config.h where in the latter file, all macros are prefixed with EXAMPLE_PROJECT_. The file public_config.h (which also has #include guards by the way) can be installed and #included in your project's public header files if need be.