WebKit has a lot of pre-processor lines like this:
#if MACRO1(MACRO2)
For example:
#if PLATFORM(MAC) || (PLATFORM(QT) && USE(QTKIT))
#include "MediaPlayerPrivateQTKit.h"
#if USE(AVFOUNDATION)
#include "MediaPlayerPrivateAVFoundationObjC.h"
#endif
...
So my first thought was that they were function-like macros, but I can't see how that would work, and I couldn't find any #defines for these macros anywhere in the source code.
I asked another engineer what it was and he's never seen multiple macros used like that inside a #if before either. I found this wiki page that talks about them but it still wasn't clear to me where they come from,
So my question then: Is this valid C++ or is it being replaced in the code by another tool/language like CMake or something else, and if it is valid C++ is there a spec anyone is aware of that talks about this?
I'm a support engineer for a C++ Static Analysis tool that isn't handling this syntax. A customer asked us to handle it, but if I'm going to take this to the senior engineer I'd like to not sound like an idiot :) So I'd like the nitty gritty if anyone knows it.
As mentioned in the wiki, in root/trunk/Source/JavaScriptCore/wtf/Platform.h we get a definition for each of these defines. For instance, the PLATFORM
macro is defined as:
#define PLATFORM(WTF_FEATURE) \
(defined WTF_PLATFORM_##WTF_FEATURE \
&& WTF_PLATFORM_##WTF_FEATURE)
The value of WTF_FEATURE
will be replaced by the platform name to create some macro named WTF_PLATFORM_WTF_FEATRE
. For instance, with WTF_FEATURE
passed into the macro as MAC
, you would end up with a expansion of WTF_PLATFORM_MAC
. The pre-processor defined
directive combined with the logical AND
is basically asking whether that macro value defined, and if it is defined, if its value is a "true" value. You would use this macro somewhere else in the pre-processor like:
#ifdef __APPLE__
#define WTF_PLATFORM_MAC 1
#end if
#define PLATFORM(WTF_FEATURE) \
(defined WTF_PLATFORM_##WTF_FEATURE \
&& WTF_PLATFORM_##WTF_FEATURE)
#if PLATFORM(MAC)
//...some code
#end if
You wouldn't use it within C++ code itself like
if (PLATFORM(MAC))
{
//...some code
}
that would cause a bunch of errors from the compiler since defined
is not a C++ keyword, and the evaluation and replacement of the macro within C++ code would end up dumping the defined
pre-processor directive into any C++ code that directly called the macro. That's not valid C++.
Thanks you to Johannes for pointing out some of these issues.
The #if
directive roughly works by replacing all macros, and then replacing all identifier and keywords of what's left by 0
and afterwards processing what's left has a constant expression according to the rules of the C++ language (the subset of those rules applicable to what's left from that replacing - quite little :)).
So PLATFORM(MAC)
may yield a 1
if MAC
is defined to be 1
, and a MAC
if it is not defined, if PLATFORM
is simply defined as
#define PLATFORM(X) X
The resulting MAC
is an identifier and will later be replaced by 0
. It's more likely that they are concatenating the X
to something like PLATFORM
, so as to support multiple queries with MAC
as argument, testing for existence of different macros. As a developer of a " C++ Static Analysis" tool you probably have access to the C++ spec. Take a look at clause 16.1
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With