Windows clang Hello World lnk4217

时间:2018-05-10 13:52:35

标签: c++ clang

我已经安装了clang 6.0版以及Visual Studio 2017.我正在编译一个简单的'hello world'应用程序:

#include <iostream>

int main()
{
  std::cout << "Hello, World!" << std::endl;
  return 0;
}

使用

clang hello.cpp

这给了我警告:

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)

我知道我可以使用clang-cl(如建议in this SO questionhere)来缓解这些警告,但是,如果不完全了解其含义,我不想这样做。

以下是我的实际问题:

  1. 这些警告意味着什么或导致它们的原因是什么?
  2. 使用clang-cl会有什么变化?使用它时我需要注意什么? (我想有理由不能一直使用它)
  3. 是否有其他方法可以不接收这些警告(关闭警告除外)?

1 个答案:

答案 0 :(得分:3)

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

这些警告是什么意思?

有一个详细的答案here(我不完全理解),但是据我了解,高层的想法是目标文件(.o文件之间不匹配) clang编译的文件以及与之链接的库文件(.lib文件)。

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

是什么原因造成的?

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

我不确定Clang如何找到这些工具。我忘了甚至都安装了它们,而它们肯定不在PATH上。我认为Clang必须以某种方式将它们从注册表中挖出。

使用clang-cl会发生什么变化?

它将更改传递给Clang编译器的开关(也称为clangclang++clang-cl,但传递了-cc1开关)和链接器(MSVC { {1}})。在较高的层次上,link.exe尝试模拟MSVC clang-cl编译器,而cl.exe ...则在做其他事情。我不确定。它不是在模仿MinGW。见下文。

详细的区别可以在相应的clang输出中看到。使用LLVM 8.0.1中的-vclang++,我看到了这些编译器切换差异:

clang-cl

在链接期间,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 传递了clang++,而-defaultlib:libcmt没有传递。

我看到的最大区别是clang-clclang-cl传递了启用线程感知的C和C ++标准库。我认为混合使用-D_MT和不使用_MT编译的模块是一个坏主意。关于-fcxx-exceptions的不匹配也令人担忧,这表明C ++异常可能不起作用。

clang-cl还将this answer推荐的标志-flto-visibility-public-std传递给相关问题。我不知道这个标志只是在抑制警告,还是在显着改变代码的编译方式。

使用时我要记住什么?

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

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

还有其他方法可以不接收这些警告吗?

就我而言,我希望Clang模拟MinGW gcc编译器并调用其链接器。为此,请按this answer,将-target x86_64-pc-windows-gnu添加到clang++命令行中:

  $ clang++.exe -target x86_64-pc-windows-gnu -o cpphello.exe cpphello.cpp

该命令不会产生警告,并且可以运行。

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

注意:您的gcc上需要一个MinGW PATH

clang与clang ++怎么样?

类似于gccclang,如果文件使用它可以识别的扩展名,例如.cc.cpp,则{em>会编译C ++代码。但是,即使您在单个命令中进行编译和链接,它也不会将C ++标准库传递给链接器。因此,通常最好在处理C ++代码时专门使用clang++

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