如何通过#define指令检测LLVM及其版本?

时间:2009-10-24 12:23:56

标签: c clang llvm c-preprocessor

我认为这个问题很清楚。我正在尝试编写一个编译器检测头,以便能够在应用程序中包含使用哪个编译器以及哪个版本的信息。

这是我正在使用的代码的一部分:

/* 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

可以这样使用:

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

有没有办法检测LLVM及其版本?和CLANG?

8 个答案:

答案 0 :(得分:72)

__llvm____clang__宏分别是检查LLVM编译器(llvm-gcc或clang)或clang的官方方式。

在使用clang时,

__has_feature__has_builtin是检查可选编译器功能的推荐方法,它们记录在here中。

请注意,您可以使用以下命令查找gcc,llvm-gcc和clang的内置编译器宏列表:

echo | clang -dM -E -

这会预处理一个空字符串并吐出编译器定义的所有宏。

答案 1 :(得分:36)

我在这里找不到答案,只能找到答案的链接,所以为了完整起见,这就是答案:

__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

我目前得到:

__clang__=1
__clang_major__=3
__clang_minor__=2
__clang_patchlevel__=0
__clang_version__="3.2 (tags/RELEASE_32/final)"

答案 2 :(得分:21)

对于clang,您不应测试其版本号,您应该使用feature checking macros检查所需的功能。

答案 3 :(得分:10)

来自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\"");

我没有找到任何方法来获取llvm和clang本身的版本,但是..

答案 4 :(得分:6)

查看Pre-defined Compiler Macros page,选择Compilers->Clang。有许多其他宏的信息可用于标准,编译器,库,操作系统,体系结构等。

答案 5 :(得分:2)

我同意最好的选择是使用具有功能宏,而不是版本宏。 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 (:

但无论如何,如果你需要编译器版本,你可以使用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;
}

输出示例:

Clang-30400000
Clang-50000000

答案 6 :(得分:1)

请注意,如果您使用llvm来破解字节码,从而#include llvm包含文件,则可以检查llvm/Config/llvm-config.h中的宏。具体而言:

/* 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"

答案 7 :(得分:0)

每个回答正确的做法都是使用功能检测宏,例如__has_feature__has_builtin等,这是正确的。如果您的用例可行,那就应该这样做。

也就是说,有时候clang不会公开您要检查的内容。例如,无法确定是否有特定的SSE / AVX或NEON功能可用(是的,有时会添加新的 ; CPU支持的指令是固定的,但有时使用现有说明添加了新功能,以填补API中的漏洞)。也许有一个错误,而clang生成了错误的机器代码。实际上,我们在SIMDe项目中经常遇到这类问题。

很遗憾,您不能依靠__clang_major__ / __clang_minor__ / __clang_patchlevel__。像Apple这样的供应商会使用clang并将其重新打包为自己的编译器,并带有自己的版本号,然后通常还会更改__clang_*__版本以匹配编译器版本,而不是上游clang的版本。例如,Apple clang 4.0实际上是经过重新包装的clang 3.1,但是它们将__clang_major__设置为4,而__clang_minor__设置为0。

我找到的最好的解决方案是使用功能检测代码来检测完全不相关的功能,而这些功能恰好以与您真正想要检测的功能相同的版本添加。我已经做了一段时间了,但是今天早些时候我终于把a header放在一起,将所有逻辑都放在一个地方。它是SIMDe的一部分,但没有任何依赖关系,是公共域(CC0)。我可能会忘记将来会进行任何改进来更新此答案,因此请检查当前版本的存储库,但这是现在的样子:

#if !defined(SIMDE_DETECT_CLANG_H)
#define SIMDE_DETECT_CLANG_H 1

#if defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION)
#  if __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) */