12

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.)

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • 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) – mvidelgauz Aug 19 '16 at 12:31
  • Tjhere is no such ability in modern C++. – Sam Varshavchik Aug 19 '16 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. – Antonio Aug 19 '16 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. – Konrad Rudolph Aug 19 '16 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. – Antonio Aug 19 '16 at 14:03
  • @KonradRudolph However, this wouldn't work if I had multiple files to include from that path. I would like cmake only to have to define the include directory, not the full path to the header file. – Antonio Aug 19 '16 at 14:04
  • I was surprised to see this: http://stackoverflow.com/questions/9096201/concatenate-string-in-c-include-filename The answers claim success, several upvotes and no comments reporting failure. Maybe the practical problem is in the `/` character... – Antonio Aug 24 '16 at 08:33

3 Answers3

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

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
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.

Sergio
  • 8,099
  • 2
  • 26
  • 52
  • @AlterMann Really weird behavior, since it builds proper names and expands headers regardless to error messages. – Sergio Aug 19 '16 at 12:58
  • Do you have a compiler for which this works? I agree one would expect it to do so... – Antonio Aug 19 '16 at 13:07
  • @Antonio I've removed `##` concatenation, and now it works, but there is a caveat, see my edit. – Sergio Aug 19 '16 at 13:58
  • To remove space, [concatenation](https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html) can help. – SimpleGuy Aug 19 '16 at 16:10
  • @SimpleGuy That's the whole point of this post, it doesn't work for include paths – Antonio Aug 22 '16 at 08:42
  • This space doesn't sound to be very portable and I could not think about the right search terms to find anything about this (tried `path space after slash`), – Antonio Aug 22 '16 at 08:50
  • I was surprised to see this: http://stackoverflow.com/questions/9096201/concatenate-string-in-c-include-filename The answers claim success, several upvotes and no comments reporting failure. Maybe the practical problem is in the `/` character... – Antonio Aug 24 '16 at 08:34
  • The example answer here isn't concatenating string literals like the question has – G Huxley Jan 15 '23 at 22:58
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)