Search code examples
c++cclangapple-developer

apple cpp breaks macro-parameter pasting


Compile the following test.cpp

# define TopLevelProject X11

#define Concat3(a,b,c) a/**/b/**/c

# define ProjectRulesFile Concat3(<,TopLevelProject,.rules>)

#include ProjectRulesFile

cpp -I. test.cpp

The expected behavior is that an include statement be generated

# 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.cpp"
# 10 "test.cpp"
# 1 "./X11.rules" 1
# 11 "test.cpp" 2



# 1 "./X11.rules" 1
# 15 "test.cpp" 2

Note that the line "./X11.rules" is indeed output

However, apple's clang cpp gives the output

# 1 "test.cpp"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 361 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.cpp" 2


test.cpp:7:10: fatal error: ' X11 .rules' file not found
#include ProjectRulesFile
         ^~~~~~~~~~~~~~~~
test.cpp:5:35: note: expanded from macro 'ProjectRulesFile'
# define ProjectRulesFile       Concat3(<,TopLevelProject,.rules>)
                                ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:3:24: note: expanded from macro 'Concat3'
#define Concat3(a,b,c) a/**/b/**/c
                       ^~~~~~~~~~~

1 error generated.

Note the malformed filename ' X11 .rules'

Apple's cpp inserted a space before the first parameter, and another between the second and third parameters of the Concat3 macro.

All versions of gcc, clang, and the msdev tools perform the proper text-substitution.

But

All versions of apple's cpp, such as those distributed by xcode, have this bug.

Is there some sort of macro parameter concatenation scheme I could use to write the Concat3 macro so that it works under apple's cpp?

Thanks


Solution

  • Concat3(a,b,c) a/**/b/**/c is an ancient, pre-standard, long deprecated method of concatenating stuff. It generally doesn't work on anything modern (that is, past 1990 or so). It may work specifically for concatenating header names with some compilers, because that's an implementation-defined area.

    6.10.2/4 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.

    Concatenating anything that is not a header name with this method is out of the question.

    There is NO standard way to concatenate a header name that works for all compilers. The standard trick

    #define CAT(a,b) CAT2(a,b)
    #define CAT2(a,b) a ## b
    

    does not work if the result is not a valid preprocessing token, which most header names aren't.