Why would one use #include_next in a project?

GccIncludeC Preprocessor

Gcc Problem Overview


To quote the iOS Documentation on Wrapper Headers:

> #include_next does not distinguish between <file> and "file" inclusion, nor does it check that the file you specify has the same > name as the current file. It simply looks for the file named, starting > with the directory in the search path after the one where the current > file was found. > > The use of `#include_next' can lead to great confusion. We recommend > it be used only when there is no other alternative. In particular, it > should not be used in the headers belonging to a specific program; it > should be used only to make global corrections along the lines of > fixincludes.

So, two questions, what is #include_next, and why would you ever need to use it?

Gcc Solutions


Solution 1 - Gcc

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 - Gcc

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 - Gcc

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCodaFiView Question on Stackoverflow
Solution 1 - GccHampus NilssonView Answer on Stackoverflow
Solution 2 - GccCraig RingerView Answer on Stackoverflow
Solution 3 - GccproductlordView Answer on Stackoverflow