How to detect LLVM and its version through #define directives?
Asked Answered
M

10

73

The question is quite clear I think. I'm trying to write a compiler detection header to be able to include in the application information on which compiler was used and which version.

This is part of the code I'm using:

/* GNU C Compiler Detection */
#elif defined __GNUC__
    #ifdef __MINGW32__
        #define COMPILER "MinGW GCC %d.%d.%d"
    #else
        #define COMPILER "GCC %d.%d.%d"
    #endif
    #define COMP_VERSION __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__
#endif

Which could be used like this:

printf("  Compiled using " COMPILER "\n", COMP_VERSION);

Is there any way to detect LLVM and its version? And CLANG?

Middleaged answered 24/10, 2009 at 12:23 Comment(2)
great question, i can't find any doco on it at allBolter
You sometimes need to know if Clang's Integrated Assembler is being used, too. The use case is modern GCC, and the compiler uses Clang as the assembler rather than an old GAS to assemble AESNI, AVX, BMI, etc. You use the Integrated Assembler because Apple's AS and LD are too old to consume assembly produced by the front-ends.Flosi
F
83

The __llvm__ and __clang__ macros are the official way to check for an LLVM compiler (llvm-gcc or clang) or clang, respectively.

__has_feature and __has_builtin are the recommended way of checking for optional compiler features when using clang, they are documented here.

Note that you can find a list of the builtin compiler macros for gcc, llvm-gcc, and clang using:

echo | clang -dM -E -

This preprocesses an empty string and spits out all macros defined by the compiler.

Frontlet answered 24/12, 2009 at 20:15 Comment(2)
Note that __GNUC__ is defined even for clang and llvm-gcc.Relativity
My specific answer is #if __has_builtin(__builtin_available) github.com/firebase/firebase-ios-sdk/commit/…Bricabrac
L
57

I cannot find an answer here, only links to answers, so for completeness, here is the answer:

__clang__             // set to 1 if compiler is clang
__clang_major__       // integer: major marketing version number of clang
__clang_minor__       // integer: minor marketing version number of clang
__clang_patchlevel__  // integer: marketing patch level of clang
__clang_version__     // string: full version number

I get currently:

__clang__=1
__clang_major__=3
__clang_minor__=2
__clang_patchlevel__=0
__clang_version__="3.2 (tags/RELEASE_32/final)"
Lindsaylindsey answered 2/5, 2013 at 15:46 Comment(2)
It's worth mentioning that this is unreliable. Vendors (like Apple) release their own versions of clang with these numbers changed to reflect their own version numbers, which have no relationship to the clang version their compiler is based on. If you're using this to try to determine if something is supported, you may end up with false positives or false negatives (depending on whether the vendor's version numbers are greater than or less than clang's).Punt
E.g. Apple clang version 15.0.0 (clang-1500.1.0.2.5) defines __clang_major__=17Layoff
E
23

For clang, you shouldn't test its version number, you should check for features you want with feature checking macros.

Edam answered 7/11, 2009 at 5:13 Comment(6)
hm, this is a good point. can you provide a link to some official material regarding this?Bolter
@Matt Joiner, I think, Chris himself is some official. Cited from his homepage nondot.org/sabre: "I'm the primary author of the LLVM Compiler Infrastructure".Dekameter
@osgx: Nevertheless he could provide links and add documentation to increase the usability of his project.Bolter
This doesn't help when working around LLVM bugs. Such as the bug in fastcall support, which was broken circa build 2335 and fixed in build 2336.Jeanene
You'd still need __clang__ to know the compiler was actually Clang.Forfend
Actually, for basic feature checking you don't need __clang__; if the __has_feature etc. macros are themselves not defined, then the features are not supported. But for the OP's purpose you would, since that is trying to print out the actual compiler version, and is not testing for features.Repellent
T
10

Snippet from InitPreprocessor.cpp:

  // Compiler version introspection macros.
  DefineBuiltinMacro(Buf, "__llvm__=1");   // LLVM Backend
  DefineBuiltinMacro(Buf, "__clang__=1");  // Clang Frontend

  // Currently claim to be compatible with GCC 4.2.1-5621.
  DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2");
  DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
  DefineBuiltinMacro(Buf, "__GNUC__=4");
  DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
  DefineBuiltinMacro(Buf, "__VERSION__=\"4.2.1 Compatible Clang Compiler\"");

I didn't find any way to get the version of llvm and clang itself, though..

Teece answered 24/10, 2009 at 14:6 Comment(1)
i guess one could for now rely on the claimed GCC versioned supported for the features, and clang/llvm for extensionsBolter
B
8

Take a look at the Pre-defined Compiler Macros page, select Compilers->Clang. There is information on many other macros for standards, compilers, libraries, OS, architectures and more.

Bolter answered 24/2, 2011 at 1:53 Comment(2)
Awesome. Just save my bacon too :)Aerometeorograph
Thanks, that's a great sources. Updated link is sourceforge.net/p/predef/wiki/CompilersIrish
P
4

Note that if you're using llvm to hack on bytecode, and thus #includeing llvm include files, you can check the macros in llvm/Config/llvm-config.h. And concretely:

/* Major version of the LLVM API */
#define LLVM_VERSION_MAJOR 3

/* Minor version of the LLVM API */
#define LLVM_VERSION_MINOR 8

/* Patch version of the LLVM API */
#define LLVM_VERSION_PATCH 0

/* LLVM version string */
#define LLVM_VERSION_STRING "3.8.0"
Papert answered 21/5, 2017 at 23:18 Comment(0)
S
2

I agree that the best choice is to use has feature macroses, not version macroses. Example with boost:

#include <boost/config.hpp>

#if defined(BOOST_NO_CXX11_NOEXCEPT)
 #if defined(BOOST_MSVC)
  #define MY_NOEXCEPT throw()
 #else
  #define MY_NOEXCEPT
 #endif
#else
 #define MY_NOEXCEPT noexcept
#endif

void my_noexcept_function() MY_NOEXCEPT; // it's example, use BOOST_NOEXCEPT (:

But anyway, if you need compiler version, you can use boost.predef:

#include <iostream>
#include <boost/predef.h>

int main() {
#if (BOOST_COMP_CLANG)
  std::cout << BOOST_COMP_CLANG_NAME << "-" << BOOST_COMP_CLANG << std::endl;
#else
  std::cout << "Unknown compiler" << std::endl;
#endif
  return 0;
}

Output examples:

Clang-30400000
Clang-50000000
Showmanship answered 16/8, 2013 at 19:36 Comment(0)
P
2

Everyone who has answered that the right thing do it is to use feature detection macros like __has_feature, __has_builtin, etc., is right. If that's possible for your use case, that's what you should do.

That said, there are times when clang doesn't expose anything specific to what you're trying to check. For example, there is no way to tell if a particular SSE/AVX or NEON function is available (and yes, new ones are added from time to time; the instructions the CPU supports are fixed, but sometimes new functions using existing instructions are added to plug a hole in the API). Or maybe there was a bug and clang was generating incorrect machine code. We actually run into these types of issues a fairly often in the SIMDe project.

Unfortunately you can't rely on __clang_major__/__clang_minor__/__clang_patchlevel__. Vendors like Apple take clang and repackage it as their own compiler with their own version numbers, and when they do they generally also change the __clang_*__ versions to match their compiler version, not upstream clang's. For example, Apple clang 4.0 is really a repackaged clang 3.1, but they set __clang_major__ to 4 and __clang_minor__ to 0.

The best solution I've found is to use the feature detection code to detect completely unrelated features which just so happen to be added in the same version as what you really want to detect. I've been doing this for a while, but earlier today I finally put together a header to keep all that logic in one place. It's part of SIMDe, but has no dependencies whatsoever and is public domain (CC0). I'll probably forget to update this answer with any improvements in the future, so please check the repo for the current version, but here is what it looks like right now:

#if !defined(SIMDE_DETECT_CLANG_H)
#define SIMDE_DETECT_CLANG_H 1

#if defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION)
#  if __has_attribute(unsafe_buffer_usage)
#    define SIMDE_DETECT_CLANG_VERSION 170000
#  elif __has_attribute(nouwtable)
#    define SIMDE_DETECT_CLANG_VERSION 160000
#  elif __has_warning("-Warray-parameter")
#    define SIMDE_DETECT_CLANG_VERSION 150000
#  elif __has_warning("-Wbitwise-instead-of-logical")
#    define SIMDE_DETECT_CLANG_VERSION 140000
#  elif __has_warning("-Waix-compat")
#    define SIMDE_DETECT_CLANG_VERSION 130000
#  elif __has_warning("-Wformat-insufficient-args")
#    define SIMDE_DETECT_CLANG_VERSION 120000
#  elif __has_warning("-Wimplicit-const-int-float-conversion")
#    define SIMDE_DETECT_CLANG_VERSION 110000
#  elif __has_warning("-Wmisleading-indentation")
#    define SIMDE_DETECT_CLANG_VERSION 100000
#  elif defined(__FILE_NAME__)
#    define SIMDE_DETECT_CLANG_VERSION 90000
#  elif __has_warning("-Wextra-semi-stmt") || __has_builtin(__builtin_rotateleft32)
#    define SIMDE_DETECT_CLANG_VERSION 80000
#  elif __has_warning("-Wc++98-compat-extra-semi")
#    define SIMDE_DETECT_CLANG_VERSION 70000
#  elif __has_warning("-Wpragma-pack")
#    define SIMDE_DETECT_CLANG_VERSION 60000
#  elif __has_warning("-Wasm-ignored-qualifier")
#    define SIMDE_DETECT_CLANG_VERSION 50000
#  elif __has_attribute(diagnose_if)
#    define SIMDE_DETECT_CLANG_VERSION 40000
#  elif __has_warning("-Wcomma")
#    define SIMDE_DETECT_CLANG_VERSION 30900
#  elif __has_warning("-Wmicrosoft")
#    define SIMDE_DETECT_CLANG_VERSION 30800
#  else
#    define SIMDE_DETECT_CLANG_VERSION 1
#  endif
#endif /* defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION) */

#if defined(SIMDE_DETECT_CLANG_VERSION)
#  define SIMDE_DETECT_CLANG_VERSION_CHECK(major, minor, revision) (SIMDE_DETECT_CLANG_VERSION >= ((major * 10000) + (minor * 1000) + (revision)))
#  define SIMDE_DETECT_CLANG_VERSION_NOT(major, minor, revision) SIMDE_DETECT_CLANG_VERSION_CHECK(major, minor, revision)
#else
#  define SIMDE_DETECT_CLANG_VERSION_CHECK(major, minor, revision) (0)
#  define SIMDE_DETECT_CLANG_VERSION_NOT(major, minor, revision) (1)
#endif

#endif /* !defined(SIMDE_DETECT_CLANG_H) */
Punt answered 9/6, 2020 at 1:19 Comment(0)
R
0

Similarly to semequ solution, we can build macros that will detect the LLVM clang version while using Apple clang by directly leveraging the Wikipedia data (which is built on the CMakeLists of the llvm-project, like this one).

That solution avoids dealing with situations where the proprietary Apple clang would incorporate Attributes or Diagnostic flags coming from a different version of LLVM clang.

#ifdef __clang__

// https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
#ifndef __apple_build_version__
#define LLVM_CLANG_MAJOR __clang_major__
#elif __clang_major__ >= 15 // Xcode 15.0 - 15.3
#define LLVM_CLANG_MAJOR 16
#elif __clang_major__ >= 14 && __clang_patchlevel__ >= 3 // Xcode 14.3
#define LLVM_CLANG_MAJOR 15
#elif __clang_major__ >= 14 // Xcode 14.0 - 14.2
#define LLVM_CLANG_MAJOR 14
#elif __clang_major__ >= 13 && __clang_minor__ >= 1 // Xcode 13.3 - 13.4
#define LLVM_CLANG_MAJOR 13
#elif __clang_major__ >= 13 // Xcode 13.0 - 13.2
#define LLVM_CLANG_MAJOR 12
#elif __clang_major__ >= 12 && __clang_patchlevel__ >= 5 // Xcode 12.5
#define LLVM_CLANG_MAJOR 11
#elif __clang_major__ >= 12 // Xcode 12.0 - 12.4
#define LLVM_CLANG_MAJOR 10
#elif __clang_major__ >= 11 && __clang_patchlevel__ >= 3 // Xcode 11.4 - 11.7
#define LLVM_CLANG_MAJOR 9
#elif __clang_major__ >= 11 // Xcode 11.0 - 11.3
#define LLVM_CLANG_MAJOR 8
#elif __clang_major__ >= 10 && __clang_patchlevel__ >= 1 // Xcode 10.2 - 10.3
#define LLVM_CLANG_MAJOR 7
#elif __clang_major__ >= 10 // Xcode 10.0 - 10.1
#define LLVM_CLANG_MAJOR 6
#elif __clang_major__ >= 9 && __clang_minor__ >= 1 // Xcode 9.3 - 9.4
#define LLVM_CLANG_MAJOR 5
#elif __clang_major__ >= 9 // Xcode 9.0 - 9.2
#define LLVM_CLANG_MAJOR 4
#else // Xcode 4.1 - 8.3
#define LLVM_CLANG_MAJOR 3
#endif// __apple_build_version__

#endif//__clang__
Rapscallion answered 18/2, 2024 at 2:32 Comment(0)
A
0

Instead of building the version string, you could use the gcc verison macro:

#include <cstdio>

#if defined(__clang__)
#   define COMPILER "Clang"
#else
#   define COMPILER "GNUC"
#endif

int main() {
    printf("Compiled using " COMPILER ": " __VERSION__ "\n");
}

Clang:

Compiled using Clang: 4.2.1 Compatible Clang 7.0.1 (Fedora 7.0.1-6.fc29)

GCC:

Compiled using GNUC: 8.3.1 20190223 (Red Hat 8.3.1-2)

Note __VERSION__ is standardized by gcc, so it likely won't exist for other compilers (Microsoft Visual C++).

Afoot answered 4/4, 2024 at 18:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.