The macro name does not expand 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 PROJECT_NAME expands as an argument to P_VERSION , and then concatenates to P_VERSION2 .
Section 16.3.3 [cpp.concat], clause 3, states
For both object-like and macro functions, before replacing the replacement list to replace the new macro names, each instance of the preprocessing marker ## in the substitution list (not from the argument) is deleted and the previous preprocessing token is combined with the next preprocessing token.
so that the pre-processing tokens associated with the pre-processing token ## are merged before the macro substitution is done in the replacement list. Therefore, PROJECT_NAME must be passed through another (functional) macro so that it can be replaced and combined using Versioning .
But in 16.3.1 [cpp.subst], clause 1, the standard indicates (emphasized by me)
After the arguments for calling the macro-like macro have been defined, the argument is replaced. A parameter in the substitution list , if only the previous token # or ## for pre-processing or follows the pre-processing ## token (see below), is replaced with the corresponding argument after all the macros contained in them have been expanded. Before replacing, each argument preprocessing token is completely replaced by a macro, as if they were the rest of the preprocessing file; no other pre-processing tokens.
that macro parameters are not subject to further macro expansion if they are adjacent to pre-processing token ## . Therefore, a function macro that receives PROJECT_NAME as an argument must not directly concatenate its argument with Versioning , but to extend PROJECT_NAME it must call another macro, similar to a function that finally performs concatenation.
So, in the above example with a call to ccache g++ ... -DPROJECT_NAME=Syren_DLL ... , PROJECT_NAME is replaced by Syren_DLL when P_VERSION(PROJECT_NAME) expands, which leads to P_VERSION2(Syren_DLL) , which then leads to the concatenation of Syren_DLL and Versioning .