更新时间:2023-11-10 18:45:28
我自己遇到了这个问题并进行了调查。
有详细的答案此处(我不完全理解),但是据我了解,高层的想法是目标文件( .o
文件)之间不匹配编译的 clang
以及与之链接的库文件( .lib
文件)。
因此,尽管该程序似乎可以运行,但仅忽略警告可能不是一个好主意。
警告是由Microsoft链接程序 link.exe
发出的,其中 clang
调用。 Clang不包括自己的链接器。默认情况下,在Windows上,它将查找Microsoft Visual Studio C编译器头,库和链接器。通过在 clang
命令行中添加 -v
(详细)开关,您可以确切地看到它在做什么。 / p>
我不确定Clang如何找到这些工具。我忘了我什至没有安装它们,而且它们肯定不在 PATH
上。我认为Clang必须以某种方式将它们从注册表中挖出。
它将更改传递给Clang编译器的开关(也称为 clang
或 clang ++
或 clang -cl
,但通过了 -cc1
开关)和链接器(MSVC link.exe
)。在较高级别上, clang-cl
尝试模拟MSVC cl.exe
编译器,而 clang
...还有其他事情。我不确定。它不是在模仿MinGW;
详细的区别可以在相应的 -v
输出中看到。使用LLVM 8.0.1中的 clang ++
和 clang-cl
,我看到了这些编译器切换差异:
clang-cl有,但clang ++缺乏:
-消除锯齿
-mllvm
-x86-asm-syntax = intel
-D_MT
-flto-visibility-public-std
--dependent-lib = libcmt
--dependent-lib = oldnames
-堆栈保护器2
-fms-volatile
-fdiagnostics-format msvc
clang ++有但clang-cl缺少:
-fcxx-exceptions
-fexceptions
在链接期间, clang ++
传递 -defaultlib:libcmt
,而 clang-cl
不传递。
我看到的最大区别是 clang-cl
传递了 -D_MT
,从而启用了线程-了解C和C ++标准库。我认为混合使用和不使用 _MT
编译的模块是个坏主意。关于 -fcxx-exceptions
的不匹配也令人担忧,这表明C ++异常可能不起作用。
clang-cl
还通过 -flto-visibility-public-std
,这是有关相关问题的答案。我不知道这个标志只是在抑制警告还是在显着改变代码的编译方式。
据我了解,当且仅当您希望Clang进行操作时,您才想使用 clang-cl
***模拟Microsoft cl.exe
编译器,包括使用其头文件并使用其库调用Microsoft链接器。
此外,我不知道在Windows上使用 clang ++
而不指定 -target
的理由(下一部分) )。如果没有 -target
, clang ++
仍将使用MSVC标头,库和链接器,但不会将所需的开关传递给模拟 cl.exe
编译器。我怀疑这将始终导致目标代码不匹配的可执行文件。
就我而言,我希望Clang模拟 MinGW gcc
编译器,然后调用其链接器。为此,请按照此答案,添加 -target x86_64-pc-windows-gnu
到 clang ++
命令行:
$ clang ++ .exe -target x86_64-pc-windows-gnu -o cpphello.exe cpphello.cpp
该命令
通过在该命令行中添加 -v
,您可以看到详细信息,包括调用MinGW ld.exe
链接器。
注意:您需要一个MinGW gcc
在您的 PATH
上!
像 gcc
, clang
将如果文件使用可识别的扩展名,则编译C ++代码,例如 .cc
或 .cpp
。但是,即使您在单个命令中进行编译和链接,它也不会将C ++标准库传递给链接器。因此,通常***在处理C ++代码时专门使用 clang ++
。
与之类似, clang -x c ++
可用于编译C ++,但不会再次将C ++标准库传递给链接器。
I have installed clang version 6.0 as well as Visual Studio 2017. I am compiling a simple 'hello world' application:
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
using
clang hello.cpp
This gives me warnings:
hello-d1b2c6.o : warning LNK4217: locally defined symbol __std_terminate
imported in function "int `public: static unsigned __int64 __cdecl
std::char_traits<char>::length(char const * const)'::`1'::dtor$2"
(?dtor$2@?0??length@?$char_traits@D@std@@SA_KQEBD@Z@4HA)
hello-d1b2c6.o : warning LNK4217: locally defined symbol _CxxThrowException
imported in function "public: void __cdecl std::ios_base::clear(int,bool)"
(?clear@ios_base@std@@QEAAXH_N@Z)
I am aware that I can mitigate these warnings by using clang-cl
(as suggested in this SO question and here), however, I do not want to do that without fully understanding the implications.
So here are my actual questions:
clang-cl
change and what do I have to keep in mind when using it? (I guess there is a reason to not use it all the time)
I ran into this issue myself and did some investigation.
There is a detailed answer here (that I do not fully understand), but the high level idea, as I understand it, is there is a mismatch between the object file (.o
file) that clang
compiled and the library file (.lib
file) that is being linked with.
Therefore, although the program seems to work, it's probably a bad idea to just ignore the warnings.
The warning is being issued by the Microsoft linker, link.exe
, which clang
invokes. Clang does not include its own linker. By default, on Windows, it looks for the Microsoft Visual Studio C compiler headers, libraries, and linker. You can see exactly what it is doing by adding the -v
(verbose) switch to the clang
command line.
I'm not sure how Clang finds these tools. I'd forgotten I even had them installed, and they certainly are not on the PATH
. I think Clang must have dug them out of the registry somehow.
It changes the switches passed to the Clang compiler (also called clang
or clang++
or clang-cl
, but with the -cc1
switch passed) and the linker (MSVC link.exe
). At a high level, clang-cl
tries to emulate the MSVC cl.exe
compiler, while clang
... does something else. I'm not sure what. It's not emulating MinGW; see below.
The detailed differences can be seen in the respective -v
outputs. Using clang++
and clang-cl
from LLVM 8.0.1, I see these compiler switch differences:
clang-cl has but clang++ lacks:
-relaxed-aliasing
-mllvm
-x86-asm-syntax=intel
-D_MT
-flto-visibility-public-std
--dependent-lib=libcmt
--dependent-lib=oldnames
-stack-protector 2
-fms-volatile
-fdiagnostics-format msvc
clang++ has but clang-cl lacks:
-fcxx-exceptions
-fexceptions
And during linking, clang++
passes -defaultlib:libcmt
, while clang-cl
does not.
The big difference I see is clang-cl
passes -D_MT
, enabling the thread-aware C and C++ standard libraries. I think it's a bad idea to mix modules compiled with and without _MT
. The mismatch regarding -fcxx-exceptions
is also concerning, suggesting that C++ exceptions might not work.
clang-cl
also passes -flto-visibility-public-std
, the flag recommended by this answer to a related question. I don't know whether this flag is merely suppressing a warning or significantly changing the way the code is compiled.
As I understand it, you want to use clang-cl
if and only if you want Clang to do its best to emulate the Microsoft cl.exe
compiler, including using its header files and invoking the Microsoft linker with its libraries.
Furthermore, I'm unaware of a reason to use clang++
on Windows without also specifying -target
(next section). Without -target
, clang++
still uses the MSVC headers, libraries, and linker, but does not pass the switches needed to emulate the cl.exe
compiler. I suspect this will always result in an executable with mismatched object code.
In my case, I want Clang to emulate the MinGW gcc
compiler and invoke its linker instead. To do that, per this answer, add -target x86_64-pc-windows-gnu
to the clang++
command line:
$ clang++.exe -target x86_64-pc-windows-gnu -o cpphello.exe cpphello.cpp
That command produces no warnings, and a working executable.
By adding -v
to that command line, you can see the details, including invocation of the MinGW ld.exe
linker.
Note: You need a MinGW gcc
on your PATH
!
Like gcc
, clang
will compile C++ code if the file uses an extension it recognizes, such as .cc
or .cpp
. However, it does not pass the C++ standard library to the linker, even when you compile and link in a single command. Therefore, it's generally best to use clang++
exclusively when working with C++ code.
Likewise, clang -x c++
can be used to compile C++, but again does not pass the C++ standard library to the linker.