13

Is there a way to concatenate 2 strings literals to form an include path?

Code stub:

#define INCLUDE_DIR "/include" #include INCLUDE_DIR "/dummy.h" 

Looking at this question, the answers point in a different direction (compiler command line). It is mentioned here that it is seemingly not possible, but I wonder if the topic has been dug enough.

(I do have an use case in which this is relevant, please focus your answers/comments on this question only.)

7
  • Are you looking for a solution for a specific compiler or you need a cross-compiler solution? (IMO it's better to add it to the question) Commented Aug 19, 2016 at 12:31
  • Tjhere is no such ability in modern C++. Commented Aug 19, 2016 at 12:43
  • @mvidelgauz I work with gcc/llvm. I wouldn't add a tag though, compiler specific solutions are in general relevant here, I would say. Commented Aug 19, 2016 at 12:47
  • The compiler command line is definitely the way to go here. This configuration belongs in a Makefile (or similar), not inside the code file. Commented Aug 19, 2016 at 13:57
  • @KonradRudolph My use case is the following. I have a big project, which uses cmake to generate makefiles/ninja.rules. Within this big project, for semplicity, all include paths are shared. However, depending on same cmake option, an include path relevant to just a few files might be excluded or not. If I change one of the cmake option, the include paths change for all files, and therefore ALL files need to be recompiled. The way I solve this, cmake generates a configuration file containing the full path to the header, and include this generated file only where that header is necessary. Commented Aug 19, 2016 at 14:03

4 Answers 4

1

It really seems this is not possible. I will report here the relevant section from Eric Postpischil's answer (he doesn't seem to be active anymore).

The compiler will do macro replacement on an #include line (per C 2011 [N1570] 6.10.2 4), but the semantics are not fully defined and cannot be used to concatenate file path components without additional assistance from the C implementation. So about all this allows you to do is some simple substitution that provides a complete path, such as:

#define MyPath "../../path/to/my/file.h" #include MyPath 

Link to documentation. In particular this section doesn't leave much hope for portable solutions:

The method by which a sequence of preprocessing tokens between a < and a > preprocessing token pair or a pair of " characters is combined into a single header name preprocessing token is implementation-defined.


For completeness, maybe something can be tried using https://stackoverflow.com/a/27830271/2436175. I'll investigate that when I have a moment...

Sign up to request clarification or add additional context in comments.

Comments

0

I'm not sure that this is exactly what you want but anyway.

#define DECORATE(x) <x> #define MAKE_PATH(root, file) DECORATE(root file) #define SYS_DIR(file) MAKE_PATH(sys/, file) #define ARPA_DIR(file) MAKE_PATH(arpa/, file) #include SYS_DIR(types.h) #include SYS_DIR(socket.h) #include ARPA_DIR(inet.h) 

Note, that generated filenames contain extra space - <sys/ types.h>, so it may not be a cross-compiler solution. But at least for me it works on Linux host on GCC 4.8 / 4.9.

P.S. It would be nice if someone could check this snippet with another compilers, e.g. MSVC.

8 Comments

@AlterMann Really weird behavior, since it builds proper names and expands headers regardless to error messages.
Do you have a compiler for which this works? I agree one would expect it to do so...
@Antonio I've removed ## concatenation, and now it works, but there is a caveat, see my edit.
To remove space, concatenation can help.
@SimpleGuy That's the whole point of this post, it doesn't work for include paths
|
0

Simply avoid the space and the concatenation (##) and use the < > it makes all simplier:

#include <QtCore/QtGlobal> #define QT_VERSION_PREFIX QT_VERSION_MAJOR.QT_VERSION_MINOR.QT_VERSION_PATCH #define _CONCATE(a, c) <a/QT_VERSION_PREFIX/a/private/c> #include _CONCATE(QtWidgets, qwidgettextcontrol_p.h) 

1 Comment

_CONCATE?!?!?
0

CONFIRMED SOLUTION ON GCC & MSVC

Despite claims out there about how this is impossible - it can be done! And it's not all that painful when you see the solution...

This is what I'm doing from top to bottom for a use case where I want to allow a collection of interdependent libraries to be built from one master project and then ported around (as headers + binaries) to other projects with variable directory layouts / include paths.

  • First, a client project sets a define to a "top level" config file path. CONDITIONALLY, defines may be provide for (include path relative) directories containing headers. This can be done from CMake, QMake, make, etc.

  • The config file contains some friendly macros setup to find the headers for specific libraries.

  • An implementation then includes the dynamic config file path and calls the macros to find other library paths.

CMake Driven Defines Example

target_compile_definitions(${TARGET_NAME} PUBLIC MY_CONFIG_PATH=\"my_core/include/myconfig.h\") target_compile_definitions(${TARGET_NAME} PUBLIC MY_INC_PATHS_OVERRIDE) target_compile_definitions(${TARGET_NAME} PUBLIC MY_CORE_INC_PATH=custom/path/my_core/include) 

(Alternative) Make Defines Example

-DMY_CONFIG_PATH=\"my_core/include/myconfig.h\" -DMY_INC_PATHS_OVERRIDE -DMY_CORE_INC_PATH=custom/path/my_core/include 

myconfig.h Example

#define MY_STR( X ) __MY_STR( X ) #define __MY_STR( X ) #X #define MY_PATH_CAT( X, Y ) X/Y #ifndef MY_INC_PATHS_OVERRIDE # define MY_CORE_INC_PATH my_core/include #endif #ifdef MY_CORE_INC_PATH # define MY_CORE_INCLUDE( FILE ) \ MY_STR( MY_PATH_CAT( MY_CORE_INC_PATH, FILE ) ) #else # define MY_CORE_INCLUDE( FILE ) MY_STR( FILE ) #endif 

Implementation

#include MY_CONFIG_PATH #include MY_CORE_INCLUDE( something.h ) 

EXTRA NOTE:

I found that when using this within a Qt framework, the macros to resolve the include paths will cause trouble in the context of generating .moc files, or doing some other kinds of Qt / Qt Creator magic requiring source parsing. But, the internals of the libs and the non Qt related lib headers still played nice with such macros in place.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.