Apparently, the clang bundled with Xcode doesn't respect the upstream __clang_major__
and __clang_minor__
values, and instead reports an Xcode user-facing version of some sort.
Here are, for reference, the values for the various MacPorts installs of clang. They seem to respect the upstream release identifiers. I get similar values when testing on Linux.
➜ prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.2 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 2
➜ prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.3 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 3
➜ prohibit-clang-3.2 /opt/local/bin/clang++-mp-3.4 -dM -E -x c /dev/null |
grep __clang_m
#define __clang_major__ 3
#define __clang_minor__ 4
However, for some reason, the Apple provided clang has __clang_major__
and __clang_minor__
versions that track the Xcode version, not the base clang revision:
➜ prohibit-clang-3.2
/Applications/Xcode-4.6.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 4
#define __clang_minor__ 2
➜ prohibit-clang-3.2
/Applications/Xcode-4.6.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
--version
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
➜ prohibit-clang-3.2
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 5
#define __clang_minor__ 0
➜ prohibit-clang-3.2
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
--version
Apple LLVM version 5.0 (clang-500.2.76) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
➜ prohibit-clang-3.2 /usr/bin/clang++ -dM -E -x c /dev/null | grep __clang_m
#define __clang_major__ 5
#define __clang_minor__ 0
This seems pretty awful, because it means you can't write conditional compilation lines like the following that will work accurately across both the Apple vendored clang, and clang built normally from the clang sources or from distro packages:
#if !defined(__clang__) || (__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ > 2))
// Thing that doesn't work for clang-3.2 due to an optimization bug.
#endif
I'd hate to need to extend that already pretty terrible preprocessor check to account for two different clang versioning schemes, one normal and one Apple. I'm not even sure how I could reliably detect that this is 'Xcode clang' rather than normal clang.
Does anyone have any suggestions on how to work around this? Is there a flag to pass to Apple's clang that will instruct it to report its 'true' version? Or has Apple doomed us to never be able to reliably use __clang_major__
and __clang_minor__
? Are these not the macros I should be using here?
If the feature checking macros don't cover what you need to check for then you do need to treat vendor releases separately as they may have very different content from the open source LLVM releases. You can use __apple_build_version__
to check for a specific Apple LLVM version.
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