Macro concatenation using compiler define
c, c++, c-preprocessor
Solution
A macro name is not expanded when it appears next to the `##` operator, so you need more layers of indirection:
#define P_VERSION2(foo) foo ## Versioning
#define P_VERSION(foo) P_VERSION2(foo)
#define VERSION_NAMESPACE P_VERSION(PROJECT_NAME)
so that `PROJECT_NAME` is expanded as the argument of `P_VERSION` and then concatenated in `P_VERSION2`.
In section 16.3.3 [cpp.concat], paragraph 3, it is specified
For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a `##` preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.
that preprocessing tokens adjacent to a `##` preprocessing token are concatenated before macro-replacement is done on the replacement list. Therefore, `PROJECT_NAME` must be passed through another (function-like) macro for it to be replaced and concatenated with `Versioning`.
But in 16.3.1 [cpp.subst], paragraph 1, the standard specifies (emphasis added by me)
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a `#` or `##` preprocessing token or followed by a `##` preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
that macro parameters are not subject to further macro-expansion if adjacent to a `##` preprocessing token. Therefore, the function-like macro that receives `PROJECT_NAME` as argument must not directly concatenate its argument with `Versioning`, but to expand `PROJECT_NAME` it must call another function-like macro that finally does the concatenation.
So in the above, with the invocation `ccache g++ ... -DPROJECT_NAME=Syren_DLL ...`, `PROJECT_NAME` is replaced with `Syren_DLL` when `P_VERSION(PROJECT_NAME)` is expanded, resulting in `P_VERSION2(Syren_DLL)` which then leads to the concatenation of `Syren_DLL` and `Versioning`.
Problem
This should be simple, but I'm struggling to figure it out. I have `PROJECT_NAME` as a compiler (`g++`) `-D` define, and I want to concatenate it with some other text to form a namespace name. My current approach is this: ``` #define VERSION_NAMESPACE PROJECT_NAME ## Versioning ``` For my current project, I expect `VERSION_NAMESPACE` to be `Syren_DLLVersioning`. Instead I get a compiler error: ``` error: 'PROJECT_NAMEVersioning' has not been declared ``` But according to the `g++` call, `PROJECT_NAME` is being defined properly: ``` ccache g++ ... -DPROJECT_NAME=Syren_DLL ... ``` Why is `PROJECT_NAME` not being replaced before the concatenation takes place?