I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.
for example, I would like to construct a macro that would be invoked like this:
#include TARGET_PATH_OF(header.h)
Which will expand to a something like this:
#include "corefoundation/header.h"
when the source is configured (in this case) for OSX
So far all attempts have failed. I'm hoping someone out there has done this before?
example of what does not work:
#include <iostream>
#include <boost/preprocessor.hpp>
#define Dir directory/
#define File filename.h
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)
using namespace std;
int main() {
// this is a test - yes I know I could just concatenate strings here
// but that is not the case for #include
cout << MyPath << endl;
}
errors:
./enableif.cpp:31:13: error: pasting formed '/filename', an invalid preprocessing token
cout << MyPath << endl;
^
./enableif.cpp:26:16: note: expanded from macro 'MyPath'
#define MyPath MakePath(File)
^
./enableif.cpp:25:40: note: expanded from macro 'MakePath'
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
^
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT'
# define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
^
/usr/local/include/boost/preprocessor/cat.hpp:29:36: note: expanded from macro 'BOOST_PP_CAT_I'
# define BOOST_PP_CAT_I(a, b) a ## b
^
1 error generated.
I tend to agree with the comment in utnapistim's answer that you shouldn't do this even though you can. But, in fact, you can, with standard-conformant C compilers. [Note 1]
There are two issues to overcome. The first one is that you cannot use the ## operator to create something which is not a valid preprocessor token, and pathnames do not qualify as valid preprocessor tokens because they include / and . characters. (The . would be ok if the token started with a digit, but the / will never work.)
You don't actually need to concatenate tokens in order to stringify them with the # operator, since that operator will stringify an entire macro argument, and the argument may consist of multiple tokens. However, stringify respects whitespace [Note 2], so STRINGIFY(Dir File) won't work; it will result in "directory/ filename.h" and the extraneous space in the filename will cause the #include to fail. So you need to concate Dir and File without any whitespace.
The following solves the second problem by using a function-like macro which just returns its argument:
#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))
#define Dir sys/
#define File socket.h
#include PATH(Dir,File)
Warning: (Thanks to #jed for passing on this issue.) If the strings being concatenated contain identifiers which are defined elsewhere as macros, then unexpected macro substitution will occur here. Caution should be taken to avoid this scenario, particularly if Dir and/or File are not controlled (for example, by being defined as a command-line parameter in the compiler invocation).
You need to also be aware than some implementations may define words which are likely to show up in a token-like fashion in a file path. For example, GCC may define macros with names like unix and linux unless it is invoked with an explicit C standard (which is not the default). That could be triggered by paths like platform/linux/my-header.h or even linux-specific/my-header.h.
To avoid these issues, I'd recommend that if you use this hack:
you use a C (or C11) standards-conformant compiler setting, and
you place the sequence very early in your source file, ideally before including any other header, or at least any header outside of the standard library.
Also, you wouldn't need the complication of the IDENT macro if you could write the concatenation without spaces. For example:
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define Dir sys
#define File socket.h
#include STR(Dir/File)
Notes
I tried it with clang, gcc and icc, as available on godbolt. I don't know if it works with Visual Studio.
More accurately, it semi-respects whitespace: whitespace is converted to a single space character.
I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.
You should be unable to (and if you are able to do so, you probably shouldn't do this).
You are effectively trying to do the compiler's job in a source file, which does not make much sense. If you want to change include paths based on the machine you compile on, this is a solved problem (but not solved in a header file).
Canonical solution:
Use an IF in your Makefile or CMakeLists.txt, use custom property pages depending on the build configuration in Visual Studio (or simply set the particular settings for your build in the OS environment for your user).
Then, write the include directive as:
#include <filename.h> // no path here
and rely on the environment/build system to make the path available when the compiler is invoked.
This works for VS2013. (It can be done easier, ofcourse.)
#define myIDENT(x) x
#define myXSTR(x) #x
#define mySTR(x) myXSTR(x)
#define myPATH(x,y) mySTR(myIDENT(x)myIDENT(y))
#define myLIBAEdir D:\\Georgy\\myprojects\\LibraryAE\\build\\native\\include\\ //here whitespace!
#define myFile libae.h
#include myPATH(myLIBAEdir,myFile)
From your description, it sound like you discovered that not every "" is a string. In particular, #include "corefoundation/header.h" looks like an ordinary string but it isn't. Grammatically, quoted text outside preprocessor directives are intended for the compiler, and compile to null terminated string literals. Quoted text in preprocessor directives is interpreted by the preprocessor in an implementation-defined way.
That said, the error in your example is because Boost pasted the second and third token : / and filename. The first, fourth and fifth token (directory, . and h) are left unchanged. This is not what you wanted, obviously.
It's a lot easier to rely on automatic string concatenation. "directory/" "filename" is the same string literal as "directory/filename" Note that there is no + between the two fragments.
Related
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.)
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...
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.
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)
Observe the following program:
#include __FILE__
main(){}
The preprocessor gets stuck in infinite recursion including a copy of itself inside itself and complaining about main() already being defined.
If I can use macros to include files,
can I derive a file name based on __FILE__ and include it?
For example, I'd like to include "foo.h" whilst inside "foo.cpp", but derive it from __FILE__.
## will concatenate macros.
It is also possible to Stringify macros.
Can it be done with the preprocessor?
The C standard specifies three forms of #include:
#include <file>
#include "file"
#include ANYTHING ELSE
In the former two cases, no macro expansion takes place, so there's no way to vary the behavior. In the third case, C99 says (§6.10.2p4):
The preprocessing tokens after #include in the directive are [macro-expanded]. The directive resulting after all replacements shall match one of the two previous forms [footnote: Note that adjacent string literals are not concatenated into a single string literal]. 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.
Slightly different, but effectively equivalent, wording appears in C++98 §16.2p4.
Any sentence with "shall" in it imposes a hard requirement: in this case, the program is ill-formed if ANYTHING ELSE expands to anything but a sequence of tokens beginning with < and ending with >, or beginning and ending with ". The exact interpretation of that sequence of tokens is implementation defined, but note that the footnote specifically forbids string-literal concatenation.
So, as the expansion of __FILE__ is a string constant, the only ways to use it in an #include are
#include __FILE__
which, as you discovered, leads to infinite recursion, and
#define LT <
#define GT >
#include LT __FILE__ etc GT
which has amusing, but useless, effects on all the compilers I can conveniently test. Assuming that the above is in a file named test.c:
GCC attempts to open a file named "test.c" etc, with the quotation marks and space included verbatim.
clang is even more literal, and looks for that same filename but with leading and trailing spaces.
MSVC macro-expands only the LT (it is my considered opinion that this is a conformance violation), complains that there is no matching >, and then attempts to open a file named __FILE__ etc GT.
(GCC's behavior is documented here; you are on your own for anything else.)
tl;dr: There is no way to do what you want from inside the preprocessor. I recommend working out the name of the file-to-be-included from your build system and notifying the compiler of it with a -D switch (on a Unixy system you will need double quotation, -DINCLUDEME='"includeme.h"'; I don't speak CMD)
The best I've come up with is this:
#define foo(x) #x
#include foo(x)
prog.cpp:2:16: error: x: No such file or directory
I have a macro I use for debugging.
#define diagnostic_arg(message,...) fprintf(stderr,message,__VA_ARGS__)
I've found that I need to use wide-chars in my program, so I would like to change just my macro and have everything work:
#define diagnostic_arg(message,...) fwprintf(stderr,message,__VA_ARGS__)
However, I need wide character strings, which are defined by putting an L in front of the string's beginning quote mark:
#define diagnostic_arg(message,...) fprintf(stderr,Lmessage,__VA_ARGS__)
Now obviously, the above line doesn't work. But if I use L message, that won't work either. So how do I write Lmessage and have it do what I would like?
You can use the token pasting operator ##:
#define diagnostic_arg(message,...) fprintf(stderr,L##message,__VA_ARGS__)
However, it might be better to use TEXT macro (if you are in Visual Studio) which will do the right thing whether UNICODE is defined or not:
#define diagnostic_arg(message,...) fprintf(stderr,TEXT(message),__VA_ARGS__)
If you're not, TEXT can be defined like this:
#ifdef UNICODE
#define TEXT(str) L##str
#else
#define TEXT(str) str
#endif
However, if you plan on using other #defines as the first argument to this macro (and really even if you don't plan on it), you will need another layer of indirection in the macro so the definition will be evaluated instead of pasted together with L as text. See Mooing Duck's answer for how to do that, his is actually the correct way to do this, but I'm not deleting this answer because I want to keep my 80 rep.
I vaguely recall the answer being something along the lines of
//glues two symbols together that can't be together
#define glue2(x,y) x##y
#define glue(x,y) glue2(x,y)
//widens a string literal
#define widen(x) glue(L,x)
#define diagnostic_arg(message,...) fprintf(stderr,widen(message),__VA_ARGS__)
Glue sometimes needs to be two macros (as I've shown), for bizzare reasons I don't quite understand, explained at the C++faq
I'm trying to create a string from multiple macros/values for use in a #include. I'm doing this to clean up some code for an initial state in a simple state system.
I have 2 default, redefinable macros (if not defined there's a default value)
#define DEFAULT_STATE StateName // name of class
#define DEFAULT_STATE_LOCATION states/ // location of header file from root
The include directive is being used from a file 4 folders in from the root, so the include should look like this
#include "../../../../states/StateName.h"
based on the example above.
So I want to define a macro from the 4 values.
../../../../
DEFAULT_STATE_LOCATION
DEFAULT_STATE
.h
into some macro, say DEFAULT_STATE_INCLUDE
so I can say
#include #DEFAULT_STATE_INCLUDE
(to stringize the value for quotes)
That way I can change the default state and the path from the root of the header file for the default state in a prefix header, and the source using the #include will not have to be updated, and I can omit the constants from redefinition every time.
I'm not including the .h in the DEFAULT_STATE macro because I use the same macro to create and instance of the default state.
I've tried using the concatenation ##, and the stringize operator, and some tricks I've found online, but nothing worked.
I can define ../../../../ and .h in their own macros if needed.
But simply
#define DEFAULT_STATE_INCLUDE ../../../../ ## DEFAULT_STATE_LOCATION ## DEFAULT_STATE ## .h
#include #DEFAULT_STATE_INCLUDE
gives tons of errors.
Any help is appreciated.
Thanks
Note that footnote 143 in section §6.10.2 "Source file inclusion" of the C99 standard says:
143) Note that adjacent string literals are not concatenated into a single string literal (see the translation
phases in 5.1.1.2); thus, an expansion that results in two string literals is an invalid directive.
Thus, any string concatenation must be done outside the source code. Token concatenation with ## is not an option; that is used to build identifiers, and the bits of the header name you are joining are not identifiers.
I think you should simply use something like:
#ifndef STATE_HEADER
#define STATE_HEADER "states/StateName.h"
#endif
#include STATE_HEADER
and leave it to the build system, not the source code, to determine that -I../../../.. is required as an option to the compiler.
You'd better pass the include directory to gcc with -I option
-I../../../..
From gcc man page:
-I dir
Add the directory dir to the list of directories to be searched for header files.
This seems relevant: Computed Includes
My reading of that is that the #define macro has to include the " (quote) characters and that you can't rely on the stringize or concatenation operators to do it for you.
Without going into the gory details I want to use a #define macro that will expand to a #include but the '#' sign is confusing the preprocessor (as it thinks I want to quote an argument.)
For example, I want to do something like this:
#define MACRO(name) #include "name##foo"
And use it thus:
MACRO(Test)
Which will expand to:
#include "Testfoo"
The humble # sign is causing the preprocessor to barf. MinGW gives me the following error:
'#' is not followed by a macro parameter
I guess I need to escape the # sign but I don't if this is even possible.
Yes, macros are indeed evil...
It is possible to insert a hash token into the preprocessed token stream. You can do it as follows:
#define MACRO(hash, name) hash include name
MACRO(#,"hello")
—expands to:
# include "hello"
However, the standard explicitly rules out any further analysis of such line for the existence of preprocessing directives [cpp.rescan]:
The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one.
As far as I remember you cannot use another preprocessor directive in define.
The problem isn't actually getting a # symbol in the output of your preprocessor.
Apparently you want the preprocessor to reparse your file, to deal with newly created #include directives as part of macro expansion. It doesn't work that way. If a line starts with #, it's an instruction for the preprocessor and interpreted. If a line doesn't start with #, it's only subject to preprocessor transformation including macro substitution. This is a once-per-line test.
MACRO(Test)
does not start with #. Therefore it is not interpreted as a preprocessor directive; instead it's subject to macro replacement rules.
This is because the # has special meaning when used in a macro.
# means quote the following token (which should be a macro parameter name)
## means concatenate the preceding and following tokens.
In your situation the # is not followed by a proper token.
So in your situation we need to go through a level of indirection:
#define QUOTE(name) #name
#define TEST(name) QUOTE(name ## foo)
#include TEST(scot)
You can't do that. Preprocessor directives are recognized before macro expansion; if the macro expands into something that looks like a preprocessor directive, that directive will not be recognized. The best you can do is create a macro for the file name:
#define MACRO(name) "name##foo"
...
#include MACRO(Test)
This might work (it works for regular #define macros with no parameters, but I haven't tested it with macros with parameters).
#define MACRO(name) <name##foo>
#include MACRO(Test)
#define HASH_SIGN #
BOOST_PP_CAT(HASH_SIGN, include)
#define PARAM_NAME Param
#define GETNAME_(a) #a
#define GETNAME(a) GETNAME_(a)
int Param;
printf("%s = %i\n", GETNAME(PARAM_NAME), PARAM_NAME);