获取 Apple clang 版本和对应的上游 LLVM 版本

Get Apple clang version and corresponding upstream LLVM version

我想了解我的 macbook 中安装了哪个版本的 clang Apple,以查看 c++11 and/or c++14 功能是否可用。 我输入了这个命令:

clang --version

//----response
Apple LLVM version 7.0.0 (clang-700.1.76)     
Target: x86_64-apple-darwin15.0.0    
Thread model: posix

但是我无法理解(clang-700.1.76)的意思。 如何将此代码转换为 clang 版本?

这是您可以检查 clang 版本 http://clang.llvm.org/cxx_status.html

中可用的 c++ 功能的站点

编译器的 (Apple) 版本号几乎没有用,因为您还需要考虑您的代码是使用 libstdc++ 还是 libc++(或任何其他标准库)编译的 -以及它们的哪个版本。

如果你想测试语言或库的特性,最好检查其他定义的值,例如__cplusplus__cpp_constexpr__cpp_variadic_templates等。它不是完美,但根据我的经验,它似乎工作得更好(如果你想要可移植性)并且所有主要编译器的支持都在改进。

每个 C++ 标准版本都为 __cplusplus 定义了一个值,一些编译器使用中间值表示 "we already started on C++14, but we are not there yet"。需要时使用>=进行测试。

其他功能测试宏类似,您可以在N4440找到当前版本。不过,并非所有编译器都实现 N4440。

这是我发现的将 Apple 的 clang 版本与 LLVM 版本相关联的最佳清单:

https://trac.macports.org/wiki/XcodeVersionInfo

以前的版本都是说对应什么LLVM版本的,但是从7.0开始,苹果决定不再这么说了。他们甚至定义了 __clang_version__ 和相关的预处理器宏来指示 Apple 版本号,而不是 LLVM 版本。所以他们对此也毫无用处。

不幸的是,看起来要查看您是否拥有某项功能的唯一方法是尝试并检查它是否有效。例如7.0.2 仍然没有默认启用 OpenMP(虽然它是 enable-able),所以我猜它仍然是 3.6,而不是 3.7。

如果您在编译器上使用 strings 命令,您可能会获得 LLVM 版本。

例如,如果您的 clang 版本将自己标识为 Apple LLVM 版本 7.0.2 (clang-700.1.81),字符串的输出将具有以下值:

LLVM 3.7.0svn

这似乎不适用于 Apple LLVM 版本 7.3.0 (clang-703.0.29)

正如 pkolbus, you can look at the /src/CMakeLists.txt to guess the corresponding Clang version. For example, Apple Clang 800.0.38 and 800.0.42.1 所暗示的那样,根据

两者似乎都基于 Clang 3.9.0
if(NOT DEFINED LLVM_VERSION_MAJOR)
  set(LLVM_VERSION_MAJOR 3)
endif()
if(NOT DEFINED LLVM_VERSION_MINOR)
  set(LLVM_VERSION_MINOR 9)
endif()
if(NOT DEFINED LLVM_VERSION_PATCH)
  set(LLVM_VERSION_PATCH 0)
endif()
if(NOT DEFINED LLVM_VERSION_SUFFIX)
  set(LLVM_VERSION_SUFFIX svn)
endif()

可以尝试使用 --verbose 选项编译 一些文件。

例如: C++ --verbose -c test1.cpp

Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix
 "/Library/Developer/CommandLineTools/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.10.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name test1.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 253.9 -v -dwarf-column-info -coverage-file /Users/az/ctest/test1.cpp -resource-dir /Library/Developer/CommandLineTools/usr/bin/../lib/clang/7.0.2 -stdlib=libc++ -fdeprecated-macro -fdebug-compilation-dir /Users/az/ctest -ferror-limit 19 -fmessage-length 130 -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.10.0 -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o test1.o -x c++ test1.cpp
clang -cc1 version 7.0.2 based upon LLVM 3.7.0svn default target x86_64-apple-darwin14.5.0

它确实打印了 LLVM svn 版本(在我们的例子中是 3.7.0)

维基百科的 Xcode 页面有 a map of Apple to LLVM versions. The LLVM column has the open-source LLVM/Clang version. From this you can look up a language feature in cppreference's chart of compiler support for language features

看看https://en.wikipedia.org/wiki/Xcode#Toolchain_versions

------------------------------------------------------------------------------------ Xcode cctools[93] ld64[94] LLVM[85] Clang version string[95] 8.3.3 898 278.4 3.9.0svn[85] 8.1.0 (clang-802.0.42)[80] 9.0 900 302.3 4.0.0?[86] 9.0.0 (clang-900.0.37)[80] 9.1 900 302.3.1 4.0.0?[87] 9.0.0 (clang-900.0.38)[80] 9.2 900 305 4.0.0?[88] 9.0.0 (clang-900.0.39.2)[80] 9.3 906 351.8 5.0.2?[89] 9.1.0 (clang-902.0.39.1)[80] 9.3.1 906 351.8 5.0.2?[89] 9.1.0 (clang-902.0.39.1)[80] 9.4 906 351.8 5.0.2?[90] 9.1.0 (clang-902.0.39.2)[80] 9.4.1 906 351.8 5.0.2?[90] 9.1.0 (clang-902.0.39.2)[80] 10.0 921.0.1 409.12 6.0.1?[91] 10.0.0 (clang-1000.11.45.2)[80] 10.1 921.0.1 409.12 6.0.1?[92] 10.0.0 (clang-1000.11.45.5)[80]

例如,Apple CLang 10.x 基于 LLVM 6.0.1。

如果您安装了 clion,在它的 preference-toolchains 中,您可能会看到 'debugger' 作为 bundled LLDB 7.0.1 .

我相信这是当前的 Apple clang 版本。 (eg.Apple LLVM 版本 10.0.1)

首先,我想说丹尼尔弗雷的回答是完全正确的;你真的应该使用 __has_feature__has_extension。若有可能。 Clang Language Extensions 页面记录了您可以检查的不同内容,这应该是您的 go-to 解决方案。

也就是说,有时您确实需要检查版本。例如,有时需要解决已在较新版本中修复或仅出现在较新版本中的编译器错误。有时会添加新功能;例如,在 clang 9 __builtin_constant_p didn't work correctly with the diagnose_if attribute 之前。有时添加了一个功能却没有相应的校验

我真的希望 clang 将上游版本号公开为预处理器宏,这样我们就可以可靠地处理这样的情况,但他们没有。您可以手动创建一个 Apple 版本号到上游的映射,这是其他几个答案所提出的,但这有一些非常明显的缺点。对我来说,致命的缺陷是它不适用于 Apple clang 以外的编译器;现在有很多基于 clang 的编译器(IBM XL C/C++,一些较新的 PGI/NVIDIA 编译器,next-gen Intel C/C++ 等)。

我的work-around是用特征检测宏估计一个版本号。例如,在 clang 11 中添加了 -Wimplicit-const-int-float-conversion,因此如果 __has_warning("-Wimplicit-const-int-float-conversion") 为真,我们可以假设上游 clang 版本为 >= 11。类似地,clang 10 添加了 -Wmisleading-indentation,clang 9 开始定义__FILE_NAME__ 预处理器宏等

我已经创建了 a small header which contains the necessary logic. It's public domain (CC0), and even though it is part of one of my projects (SIMDe) 它不依赖于任何其他文件的任何其他内容,因此您可以为自己的项目自由窃取它而无需复制所有 SIMDe。

显然该文件需要对每个版本的 clang 进行新测试,因此如果您需要能够检查更新的编译器,它确实需要偶尔更新,所以我建议从 SIMDe git 存储库(我不太可能使这个答案保持最新),但现在的支票是这样的:

#if defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION)
#  if __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("-Wbitfield-enum-conversion")
#    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 39000
#  elif __has_warning("-Wdouble-promotion")
#    define SIMDE_DETECT_CLANG_VERSION 38000
#  elif __has_warning("-Wshift-negative-value")
#    define SIMDE_DETECT_CLANG_VERSION 37000
#  elif __has_warning("-Wambiguous-ellipsis")
#    define SIMDE_DETECT_CLANG_VERSION 36000
#  else
#    define SIMDE_DETECT_CLANG_VERSION 1
#  endif
#endif /* defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION) */

我认为此方法的最大问题实际上与我所知道的检测上游 clang 版本的所有其他尝试相同:不一定有与相关代码相对应的 clang 版本。据我所知,大多数基于 clang 的编译器实际上并不是基于发布,而是一些随机提交(可能是他们想要基于其工作的分支的最新提交)。这意味着,例如,如果问题在 clang $N 开发周期的后期得到修复,Apple 的分支通常可能与 clang $N 相同,但不包含错误修复。相反,也许 Apple 会 back-port 来自 clang $N+1 的修复程序和 clang $N 中存在的错误将在 Apple 版本中得到修复。

作为您的终端输出

clang --version
//----response
Apple LLVM version 7.0.0 (clang-700.1.76)     
Target: x86_64-apple-darwin15.0.0    
Thread model: posix

第一行“Apple LLVM version 7.0.0 (clang-700.1.76)”的意思是: 您的 Xcode7.1 嵌入了 Clang7.0.0Clang7.0.0 标识符:clang-700.1.76)。

从这个 website,我知道你的 Clang 版本是 7.0.0。 如果 Clang 版本是 >= Clang5.0, that Clang support C++11 or C++14.