如何告诉 Clang 停止伪装成其他编译器? [英] How to tell Clang to stop pretending to be other compilers?

查看:30
本文介绍了如何告诉 Clang 停止伪装成其他编译器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我过去遇到过这个问题: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= 标志覆盖这些值.它接受一个带点的版本元组,例如 19.00.23506.更改 MSVC 兼容版本使 clang 的行为更像那个版本的 MSVC.例如,-fms-compatibility-version=19 将启用 C++14 功能并将 char16_t 和 char32_t 定义为内置类型.

解决方案

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

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

#if defined(__GNUC__) &&!defined(__llvm__) &&!defined(__INTEL_COMPILER)#define REAL_GCC __GNUC__//可能#万一

Clang 前端定义了 __clang__,但其他使用 LLVM 后端的前端也定义了 __llvm__(例如 IBM XL C/C++ 版本 13.1.1 到 16.1).仅排除 __clang__ 而不是 __llvm__ 可能更好,具体取决于您想要排除它的原因.(例如,出于解析原因,与优化原因,例如 LLVM 在进行内联之前评估 __builtin_constant_p(),因此它对内联函数的 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 特定的宏,只有它支持的 C 语言的 GNU 方言版本.(GNU C 是一种语言,GCC 是该语言的编译器. GCC 的 __GNUC_MINOR__/__GNUC_PATCHLEVEL__ 宏将两者混为一谈,不幸的是.)>

Clang 根据声称完全兼容的 gcc 版本定义了 __GNUC__/__GNUC_MINOR__/__GNUC_PATCHLEVEL__.(可能仅适用于 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__)…/* 测试 GCC >3.2.0 */#if GCC_VERSION >30200

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

I've run into this issue in the past: LLVM defines __GNUC__, but it can't consume a program GCC can. I'm experiencing it again on Windows: LLVM defines _MSC_VER, but it can't consume the same program VC++ can. The aggravating thing (for me) is we have specialized code paths for LLVM Clang and Apple Clang (different defines due to different version schemes), and we have to fight with the tool to get it to use them.

How do we tell Clang to stop pretending to be other compilers? Is there a switch or option to do it?


The Clang docs discuss the unwanted MS behavior, but they don't say how to stop it:

For compatibility with existing code that compiles with MSVC, clang defines the _MSC_VER and _MSC_FULL_VER macros. These default to the values of 1800 and 180000000 respectively, making clang look like an early release of Visual C++ 2013. The -fms-compatibility-version= flag overrides these values. It accepts a dotted version tuple, such as 19.00.23506. Changing the MSVC compatibility version makes clang behave more like that version of MSVC. For example, -fms-compatibility-version=19 will enable C++14 features and define char16_t and char32_t as builtin types.

解决方案

__GNUC__ doesn't mean GCC specifically. All compilers that support GNU C extensions define it, including clang and ICC.

The normal way to detect specifically GCC is by excluding other "compatible" compilers

#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
#define REAL_GCC   __GNUC__ // probably
#endif

The Clang front-end defines __clang__, but other front-ends that use the LLVM back-end also define __llvm__ (e.g. IBM XL C/C++ versions 13.1.1 through 16.1). It might be better to just exclude __clang__ instead of __llvm__, depending on why you want to exclude it. (e.g. for parsing reasons, vs. for optimization reasons like LLVM evaluating __builtin_constant_p() before doing inlining, so it's useless on args of an inline function.)

See also https://sourceforge.net/p/predef/wiki/Compilers/ for a large list.

https://blog.kowalczyk.info/article/j/guide-to-predefined-macros-in-c-compilers-gcc-clang-msvc-etc..html came up in google results, too, but is less complete.


The thing you should be complaining about is that GCC itself doesn't define a GCC-specific macro you can detect, only the version of the GNU dialect of C it supports. (GNU C is a language, GCC is a compiler for that language. GCC's __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ macros conflate the two, unfortunately.)

Clang defines __GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ according to the version of gcc that it claims full compatibility with. (Probably only for stuff that GCC documentation guarantees will work, not for stuff that happens to work with that version or later of gcc. For GCC itself, documented = supported. Being accepted by the compiler doesn't imply it's supported and guaranteed for future GCC versions. That might be how clang justifies claiming support for some GNU C versions).

For example, clang 7.0.1 defines GNUC/MINOR/PATCHLEVEL as 4/2/1, i.e. compat with GCC 4.2.1

e.g. from the GCC manual

#define GCC_VERSION (__GNUC__ * 10000 
                     + __GNUC_MINOR__ * 100 
                     + __GNUC_PATCHLEVEL__)
…
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200

If you're testing for a specific GNU C feature that recent GCC supports but recent clang doesn't support (yet), you should probably be doing something like that.

这篇关于如何告诉 Clang 停止伪装成其他编译器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆