So I think what I am trying to do is just impossible in GCC due to macro expansion having to result in a preprocessor token. This works fine in MSVC++ for what it is worth but I can not find a comparable
So I think this is impossible in GCC (Works fine in VC++) due to macro expansion having to be preprocessor tokens and what is considered a separator between the tokens.
I am attempting to link in a specific version of a library, in this example it is Lua 5.3.1. I have the files in extracted to my source folder so that they can be found in the sub folder 'lua-5.3.1\src' and I would like to write a macro that I can use to prefix the header files with that path. Something simple like LUA_PATH(_file)
that would expand into "lua-5.3.1/src/_file"
. Normally I would just use the compiler flags to give a different sub-folder to search through but due to how the projects I am working on are set up, that is exactly what I can not do and what I am trying to find another way around having to maintain the include paths all over the place.
Here is the little file I wrote (that does not compile, but I can run it through cpp to see what it gives me)
#define LUASRC lua-5.3.1/src/
#define STRINGIFY(_s) #_s
#define ADDLUAPATH(_path, _file) STRINGIFY(_path ## _file)
#define EVALUATOR(_path, _file) ADDLUAPATH(_path,_file)
#define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
void main (void)
{
OUTPUTOFMACROHERE => LUA_PATH(lua.h)
}
This gives me the following output from running cpp on the file
$ cpp temp.c
# 1 "temp.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "temp.c"
void main (void)
{
temp.c:1:29: error: pasting "/" and "lua" does not give a valid preprocessing token
#define LUASRC lua-5.3.1/src/
^
temp.c:3:44: note: in definition of macro 'ADDLUAPATH'
#define ADDLUAPATH(_path, _file) STRINGIFY(_path ## _file)
^
temp.c:5:25: note: in expansion of macro 'EVALUATOR'
#define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
^
temp.c:5:35: note: in expansion of macro 'LUASRC'
#define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
^
temp.c:9:23: note: in expansion of macro 'LUA_PATH'
OUTPUTOFMACROHERE => LUA_PATH(lua.h)
^
OUTPUTOFMACROHERE => "lua-5.3.1/src/lua.h"
}
The truly frustration part of this is that the second from last line is exactly the output I am trying to get. It is just that GCC considers getting there an error.
The issue is the / character at the end of the path. If you take the / out at the end of the LUASRC definition and run it you get OUTPUTOFMACROHERE => "lua-5.3.1/srclua.h"
with out any error.. except that the path is invalid. I can not find a place to put the character anywhere to get it into the output quoted string. I have tried adding it in on its own like _path ## / ## _file
or moving it to the value passed in like LUA_PATH(/lua.h)
. This just complains about what is being combined with it (src or lua) as an invalid preprocessor token.
I have tried just using the strings for the preprocessor to concatenate but #include "string" "string"
just seems to try and include both of those strings as separate paths. Clearly a folder can not be opened and the exact file can not be found with out searching sub folders. This has also been the result of having half of the variables (the path or the file) to be a string to be added to the other expanded and stringified value. It also is the result of simply trying to prefix my files with the path to be expanded #include LUASRC"lua.h"
(GCC documentation said if it does not find a < or a " it considers the value for macro expansion)
Is there another strategy to get it to like the / in a macro definition that I am missing? Would love to know.
For what its worth I am using gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
EDIT: The logic to actually do it but more important the reasons Not to do this are provided in the link of the answer marked below. For quick point of reference of all things however, this is what my little temp.c file ended up looking like
#define LUASRC lua-5.3.1/src/
#define EXPAND(_a) _a
#define STRINGIFY(_s) #_s
#define EVALUATOR(_args) STRINGIFY(_args)
#define LUA_PATH(_file) EVALUATOR(EXPAND(LUASRC)EXPAND(_file))
void main (void)
{
OUTPUTOFMACROHERE => LUA_PATH(lua.h)
}
It is not that "gcc thinks it is an error". It is an error. ("If the result [of the concatenation] is not a valid preprocessing token, the behavior is undefined.", C11 §6.10.3.3/3).
But that doesn't matter because you can stringify more than one token; there is no need to concatenate. You just have to watch out for whitespace.
See https://stackoverflow.com/a/32077478/1566221 for an example.