Windows Clang Hello World LNK4217

Jer*_*der 6 c++ clang

我已经安装了clang 6.0版以及Visual Studio2017。我正在编译一个简单的“ hello world”应用程序:

#include <iostream>

int main()
{
  std::cout << "Hello, World!" << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用

clang hello.cpp
Run Code Online (Sandbox Code Playgroud)

这给了我警告:

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)
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过使用clang-cl(如本SO问题此处的建议)减轻这些警告,但是,我不想在没有完全理解其含义的情况下这样做。

所以这是我的实际问题:

  1. 这些警告是什么意思或导致它们的原因?
  2. 使用clang-cl更改有什么意义,使用更改时我必须牢记什么?(我认为有理由不一直使用它)
  3. 还有其他方法可以不接收这些警告(关闭警告除外)?

Sco*_*eak 6

我自己遇到了这个问题并做了一些调查。

这些警告是什么意思?

有一个详细的答案在这里(我不完全理解),但高层次的想法,据我所知,是有目标文件(之间的不匹配.o该文件)clang编译和库文件(.lib文件)被与连接。

因此,尽管该程序似乎可以运行,但忽略警告可能是个坏主意。

是什么导致了它们?

该警告是由Microsoft链接,发行link.exe,其中clang所调用。Clang 不包含自己的链接器。默认情况下,在 Windows 上,它会查找 Microsoft Visual Studio C 编译器标头、库和链接器。通过将-v(详细)开关添加到clang命令行,您可以准确地看到它在做什么。

我不确定 Clang 如何找到这些工具。我忘了我什至安装了它们,而且它们肯定不在PATH. 我认为 Clang 一定是以某种方式将它们从注册表中挖出来的。

使用 clang-cl 有什么变化?

它更改传递给 Clang 编译器(也称为clangorclang++clang-cl,但需要-cc1传递开关)和链接器 (MSVC link.exe)的开关。在高层次上,clang-cl尝试模拟 MSVCcl.exe编译器,而clang... 做其他事情。我不确定是什么。它不是在模仿 MinGW;见下文。

详细的差异可以在相应的-v输出中看到。使用clang++clang-cl从 LLVM 8.0.1,我看到这些编译器开关差异:

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
Run Code Online (Sandbox Code Playgroud)

并且在链接期间,clang++通过-defaultlib:libcmt,而clang-cl不会。

我看到的最大区别是clang-clpasss -D_MT,启用线程感知 C 和 C++ 标准库。我认为混合使用和不使用_MT. 不匹配-fcxx-exceptions也令人担忧,这表明 C++ 异常可能不起作用。

clang-cl也通过了-flto-visibility-public-std这个相关问题的答案推荐的标志。我不知道这个标志是只是抑制警告还是显着改变了代码的编译方式。

使用时需要注意什么?

据我了解,clang-cl当且仅当您希望 Clang 尽最大努力模拟 Microsoftcl.exe编译器时,您才希望使用它,包括使用其头文件并使用其库调用 Microsoft 链接器。

此外,我不知道clang++在没有指定的情况-target下在 Windows上使用的原因(下一节)。没有-target,clang++仍然使用 MSVC 头文件、库和链接器,但不传递模拟cl.exe编译器所需的开关。我怀疑这总是会导致可执行文件的目标代码不匹配。

还有其他方法不会收到这些警告吗?

就我而言,我希望 Clang 模拟MinGW gcc编译器并调用其链接器。为此,根据此答案,添加-target x86_64-pc-windows-gnuclang++命令行:

  $ clang++.exe -target x86_64-pc-windows-gnu -o cpphello.exe cpphello.cpp
Run Code Online (Sandbox Code Playgroud)

该命令不会产生任何警告,并且是一个可以运行的可执行文件。

通过添加-v到该命令行,您可以查看详细信息,包括 MinGWld.exe链接器的调用。

注意:您gccPATH!

铿锵与铿++呢?

Like gcc,如果文件使用它识别的扩展名,例如或,clang 则将编译 C++ 代码。但是,它不会将 C++ 标准库传递给链接器,即使您在单个命令中编译和链接也是如此。因此,通常最好在使用C++ 代码时专门使用。.cc.cppclang++

同样,clang -x c++可用于编译 C++,但再次不将 C++ 标准库传递给链接器。