如何告诉Clang不要假装成其他编译器?

jww*_*jww 9 gcc llvm clang visual-c++

我过去遇到过这个问题:LLVM定义__GNUC__,但它不能消耗GCC可以的程序.我在Windows上再次遇到它:LLVM定义_MSC_VER,但它不能使用VC++可以使用的相同程序.加重的事情(对我来说)是我们有LLVM Clang和Apple Clang的特殊代码路径(由于不同的版本方案而定义不同),我们必须与该工具对抗以使其使用它们.

我们如何告诉Clang不要假装成其他编译器?有没有开关或选项吗?


Clang文档讨论了不需要的MS行为,但他们没有说如何阻止它:

为了与使用MSVC编译的现有代码兼容,clang定义了_MSC_VER和_MSC_FULL_VER宏.这些默认值分别为1800和180000000,使得clang看起来像Visual C++ 2013的早期版本.-fms-compatibility-version = flag会覆盖这些值.它接受虚线版本元组,例如19.00.23506.更改MSVC兼容性版本使clang表现得更像MSVC版本.例如,-fms-compatibility-version = 19将启用C++ 14功能,并将char16_t和char32_t定义为内置类型.

Pet*_*des 10

__GNUC__并不特指 GCC。所有支持 GNU C 扩展的编译器都定义了它,包括 clang 和 ICC。

专门检测 GCC 的正常方法是排除其他“兼容”编译器

#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
#define REAL_GCC   __GNUC__ // probably
#endif
Run Code Online (Sandbox Code Playgroud)

Clang 前端定义了__clang__,但其他使用 LLVM 后端的前端也定义了__llvm__(例如 IBM XL C/C++ 版本 13.1.1 到 16.1)。最好只排除__clang__而不是__llvm__,这取决于您想排除它的原因。(例如,出于解析原因,而不是出于优化原因,例如__builtin_constant_p()在进行内联之前进行LLVM 评估,因此在内联函数的 args 上是无用的。)

另请参阅https://sourceforge.net/p/predef/wiki/Compilers/以获取大列表。

https://blog.kowalczyk.info/article/j/guide-to-predefined-macros-in-c-compilers-gcc-clang-msvc-etc..html也出现在谷歌结果中,但不够完整.


您应该抱怨的是 GCC 本身并没有定义您可以检测到的特定于 GCC 的宏,只有它支持的 GNU 方言 C 版本。(GNU C 是一种语言,GCC 是该语言的编译器。不幸的是, GCC 的__GNUC_MINOR__/__GNUC_PATCHLEVEL__宏将两者混为一谈。)

铛定义__GNUC__/ __GNUC_MINOR__/__GNUC_PATCHLEVEL__根据gcc的版本,它声称具有完全兼容性。(可能仅适用于 GCC 文档保证可以工作的内容,而不适用于该版本或更高版本的 gcc 的内容。对于 GCC 本身,已记录=支持。被编译器接受并不意味着它得到支持并保证未来GCC 版本。这可能是 clang 声称支持某些 GNU C 版本的理由)。

例如,clang 7.0.1 将 GNUC/MINOR/PATCHLEVEL 定义为 4/2/1,即与 GCC 4.2.1 兼容

例如来自GCC 手册

#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)
…
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200
Run Code Online (Sandbox Code Playgroud)

如果您正在测试最近的 GCC 支持但最近的 clang 不支持的特定 GNU C 功能(还),您可能应该做类似的事情。

  • *“__GNUC__ 并不是专门指 GCC。”* - `__GNUC__` 指的是 GCC 编译器。它[详细记录](https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros) 并且已经存在多年。甚至 GCC 的人也告诉 Clang 停止定义它,因为它意味着 GCC 编译器。 (4认同)
  • *“专门检测 GCC 的正常方法是排除其他“兼容”编译器”* - 不,这不是正常方法。检测 GCC 的正常方法是存在 `__GNUC__`。ICC 有一个开关来禁用该行为。 (4认同)
  • @jww:如果 GCC 有一个自己的宏就好了,但事实上的现实是我在这个答案中描述的,非 GCC 编译器决定定义 `__GNUC__` 来表示与某些版本的兼容性海湾合作委员会。(无论这是否完全准确。)在 MacOS 上有太多现有的 Clang 安装无法忽略,即使 clang 明天会改变。(半相关,MacOS 甚至安装了一个 `gcc`,它实际上是 `clang` 的符号链接,也会导致 SO 问题的混淆。) (4认同)

Mat*_*man 10

从版本 10 开始,clang 似乎有了一个选项。请参阅clang 的文档

-fgnuc-版本=

该标志控制GNUC和相关宏的值。该标志不会启用或禁用 Clang 中实现的任何 GCC 扩展。将版本设置为零会导致 Clang 保留GNUC和其他 GNU 命名空间宏(例如GXX_WEAK)未定义。

因此,要禁用此行为,请-fgnuc-version=0在 clang 命令行上指定。

  • 在将这个标志与 clang 11、libstdc++、linux 和 -D_GLIBCXX_DEBUG 一起使用后,我在标准库中遇到了一百万个错误。所以,Peter Cordes的回答仍然是唯一的解决方案。 (3认同)

Adr*_*thy 2

我们如何告诉 Clang 不要冒充其他编译器?

我不知道该怎么做,也不知道它是否可行。你为什么要这样做?我感觉您想这样做是为了解决问题,但也许有更好的解决方案。

[在 Windows 上,] LLVM 定义 _MSC_VER,

因为您可能使用标准库来检查它以生成兼容的代码。

Clang 在 Windows 上的目标不仅仅是生成在 Windows 上运行的独立代码,而且还生成可以与使用 VC++ 编译的库链接的代码。从源代码来看,应该无法区分是用clang还是VC++编译的。

如果您希望能够调用现有的 DLL,并且检查其头文件_MSC_VER,则需要设置是否使用 VC++ 还是 clang。

但是 [Windows 上的 clang] 无法使用 VC++ 可以使用的相同程序。

自从写这个问题以来,Clang 在 Windows 上的功能已经有了很大的改进。几个主要项目现在在其 Windows 版本中使用 clang。

如果您发现 VC++ 接受而 clang 不接受的正确程序,请提交错误报告。在大多数情况下,这可能是一个疏忽。有少量功能和 VC++ 扩展未在 clang-on-Windows 中实现,因为它们的优先级不够高。如果它们是您的优先事项,请告诉我们。

  • *“你为什么要这样做?”* - 我们浪费了近三个人月的时间来修复 Clang 错误,因为它无法为它所伪装的编译器使用程序。毫不奇怪,PowerPC 上的情况变得更糟。Clang 假装是 GCC 和 IBM XL/C,并且不能使用任一编译器的程序。我厌倦了浪费时间支持 Clang。我们不再希望 Clang 冒充其他编译器。相反,Clang 可以使用直接的 C/C++ 代码。换句话说,那些干这种蠢事的混蛋不会受到惩罚;他们只会受到惩罚。我们为他们的垃圾行为付出代价。 (9认同)
  • C++ 既是一种语言,也是一个库。除了特殊情况外,_“直接 C/C++ 代码”_ 依赖于需要了解编译器工作细节的库,并且编译器本身依赖于其标准库实现。您尝试在 Windows 上使用哪些库(例如 VC++ 的标准库、libstd、libc++ 等)?您发现哪些代码 VC++ 可以编译但 clang 不能编译?我(以及我团队中的其他“混蛋”)感谢您提交 LLVM 错误报告以及您对 LLVM 和 clang 所做的任何贡献。 (4认同)
  • 因此,即使对于那些应该有效的东西,我也不会感到惊讶 libcrypto++ 以纯 C/++ 代码所不具备的新方式运行编译器,并遇到真正的编译器错误。但请记住,在其他问答中,我看到 jww 基本上责怪 GCC 没有按照他希望的方式工作,因为与 MSVC 不同的设计理念是必须启用“-mwhatever”才能使用内在函数,这对于他们想要使用 libcrypto++ 的方式。或类似的东西。因此,我对他的咆哮持保留态度,尽管其中经常有一些合理的抱怨。 (2认同)