Why would one use #include_next in a project?

Solution 1:

It is used if you want to replace a default header with one of your own making, for example, let's say you want to replace "stdlib.h". You would create a file called stdlib.h in your project, and that would be included instead of the default header.

#include_next is used if you want to add some stuff to stdlib.h rather than replace it entirely. You create a new file called stdlib.h containing:

#include_next "stdlib.h"
int mystdlibfunc();

And the compiler will not include your stdlib.h again recursively, as would be the case with plain a #include, but rather continue in other directories for a file named "stdlib.h".

Solution 2:

It's handy if you're supporting multiple versions of something. For example, I'm writing code that supports PostgreSQL 9.4 and 9.6. A number of internal API changes exist, mostly new arguments to existing functions.

Compatibility headers and wrapper functions

I could write compatibility headers with static inline wrapper functions with new names for everything, basically a wrapper API, where I use the wrapper name everywhere in my code. Say something_compat.h with:

#include "something.h"

static inline something*
get_something_compat(int thingid, bool missing_ok)
{
    assert(!missing_ok);
    return get_something(thingid);
}

but it's ugly to scatter _compat or whatever suffixes everywhere.

Wrapper header

Instead, I can insert a compatibility header in the include path when building against the older version, e.g. compat94/something.h:

 #include_next "something.h"

 #define get_something(thingid, missing_ok) \
 ( \
     assert(!missing_ok), \
     get_something(thingid) \
 )

so the rest of the code can just use the 9.6 signature. When building against 9.4 we'll prefix -Icompat94 to the header search path.

Care is required to prevent multiple evaluation, but if you're using #include_next you clearly don't mind relying on gcc. In that case you can also use statement expressions.

This approach is handy when the new version is the "primary" target, but backward compatibility for an older version is desired for some limited time period. So you're deprecating the older versions progressively and trying to keep your code clean with reference to the current version.

Alternatives

Or be a sensible person, use C++, and use overloaded functions and template inline functions :p

Solution 3:

include_next is used as a preprocessor directive to tell the compiler to exclude the search paths up to and including filename file.h from resolving to this header file. The typical need is when two header files of the same name need to be used. Use such features sparingly and only when absolutely necessary.

For example:

source file.c contents with the usual file.h from path 1:
#include <file.h>
 int main() {
     printf("out value: %d", out_val);
     exit 0;
     }
file.h header file in path 1 contents with file.h from path 2 included: include_next instructs that path 1 sub directory not be used as search path for file.h and instead use path 2 sub directory as search path. This way you can have 2 files of the same name without the fear of invoking a circular reference to itself.
# include_next <file.h>
int out_val = UINT_MAX - INT_MAX;
file.h in path 2 contents
#define INT_MAX 1<<63 - 1
#define UINT_MAX 1<<64 - 1