Windows clang Hello World lnk4217

Posted

技术标签:

【中文标题】Windows clang Hello World lnk4217【英文标题】: 【发布时间】:2018-05-10 13:52:35 【问题描述】:

我已经安装了 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 question 和here)来缓解这些警告,但是,如果不完全了解其含义,我不想这样做。

所以这是我的实际问题:

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

【问题讨论】:

你应该用clang++编译。 @BaummitAugen 为什么?这不会影响警告。 来自用户手册:clang-cl is an alternative command-line interface to Clang, designed for compatibility with the Visual C++ compiler, cl.exe.link 因为它确保您调用 C++ 前端,而不是 C 前端。这并不奇怪,我不是故意将其作为答案发布的。 @BaummitAugen 感谢您对我的教育(顺便说一句,这不是讽刺)。对于任何想了解更多信息的人:***.com/a/20052006/5909613 【参考方案1】:

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

这些警告是什么意思?

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

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

是什么原因造成的?

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

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

使用 clang-cl 有什么变化?

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

可以在各自的-v 输出中看到详细的差异。使用 LLVM 8.0.1 中的 clang++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-cl 不会。

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

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

使用时需要注意什么?

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

此外,我不知道在 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 链接器的调用。

注意:您的 PATH 上需要 MinGW gcc

clang 与 clang++ 怎么样?

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

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

【讨论】:

以上是关于Windows clang Hello World lnk4217的主要内容,如果未能解决你的问题,请参考以下文章

windows学习记录----hello world与窗口创建

01 Windows编程——Hello World

Windows10 IoT开发系列“Hello,World!”指导

Windows对应的"Hello,world"程序

"Hello World!" for Microsoft Windows

超详细SDK Hello World