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

发布于 2024-08-09 00:17:05 字数 511 浏览 3 评论 0 原文

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

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

紫竹語嫣☆ 2024-08-16 00:17:06

您可以使用 gcc verison 宏来代替构建版本字符串:

#include <cstdio>

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

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

Clang

使用 Clang 编译:4.2.1 兼容 Clang 7.0.1 (Fedora 7.0.1-6.fc29)

GCC:

使用 GNUC 编译:8.3.1 20190223(Red Hat 8.3.1-2)

注意 __VERSION__ 由 gcc 标准化,因此其他编译器 (Microsoft Visual C++) 可能不存在。

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++).

雾里花 2024-08-16 00:17:05

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

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

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

echo | clang -dM -E -

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

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.

爱人如己 2024-08-16 00:17:05

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

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

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)"
听风吹 2024-08-16 00:17:05

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

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

楠木可依 2024-08-16 00:17:05

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

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..

傲影 2024-08-16 00:17:05

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

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.

苄①跕圉湢 2024-08-16 00:17:05

请注意,如果您使用 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"

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"
累赘 2024-08-16 00:17:05

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

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
雨轻弹 2024-08-16 00:17:05

每个回答正确做法是使用特征检测宏(如 __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。

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

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

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) */
始于初秋 2024-08-16 00:17:05

与 semequ 解决方案类似,我们可以构建宏,通过直接利用 维基百科数据(基于 llvm 项目的 CMakeLists 构建,例如 这个)。

该解决方案避免了处理专有 Apple clang 合并来自不同版本的 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__

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__
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文