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
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…