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

问题描述 投票:0回答:8

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

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

/* 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及其版本?还有叮当声?

c clang llvm c-preprocessor
8个回答
81
投票

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

__has_feature
__has_builtin
是使用 clang 时检查可选编译器功能的推荐方法,它们记录在 here

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

echo | clang -dM -E -

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


57
投票

我在这里找不到答案,只能链接到答案,因此为了完整起见,这里是答案:

__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)"

23
投票

对于 clang,您不应该测试其版本号,您应该使用 功能检查宏来检查您想要的功能。


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 本身的版本..


7
投票

查看预定义编译器宏页面,选择编译器->Clang。还有关于标准、编译器、库、操作系统、体系结构等的许多其他宏的信息。


3
投票

请注意,如果您使用 llvm 来破解字节码,从而

#include
ing 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"

2
投票

我同意最好的选择是使用has feature宏,而不是版本宏。 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

2
投票

每个回答正确做法是使用特征检测宏(如

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

© www.soinside.com 2019 - 2024. All rights reserved.