如何使用 link.exe 进行静态链接

Posted

技术标签:

【中文标题】如何使用 link.exe 进行静态链接【英文标题】:How to statically link using link.exe 【发布时间】:2010-12-14 01:35:22 【问题描述】:

我一直在尝试使用 Visual Studio 2008 命令行工具在 Windows 上静态链接一个名为 Poco 的 C++ 库。

我构建我的程序:

cl /I..\poco\lib /c myapp.cpp
link /libpath:..\poco\lib myapp.obj PocoNet.lib

这会导致运行时需要 PocoNet.dll 和 PocoFoundation.dll 的 exe。

我花了一些时间阅读 Windows 中的链接,并了解到 cl /MT 静态链接到标准库,而 cl /MD 动态链接。

我尝试指定/MT,但这似乎并没有改变任何东西;我的应用程序仍然需要 Poco DLL。 (我也怀疑/MT 是默认行为。)

查看..\poco\lib下,我发现还有一个PocoNetmt.lib,但指定它而不是PocoNet.lib会导致一堆LNK2005错误(“已经定义”):

msvcprt.lib(MSVCP90.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in exp.obj

然后我尝试堆叠更多标志:

/verbose:lib:有助于查看正在发生的事情

/Zl: 结果和之前一样

/nodefaultlib:libcmt.lib /nodefaultlib:msvcprt.lib: 收到此错误:

PocoFoundationmt.lib(Exception.obj) : warning LNK4217: locally defined symbol ??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ (public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)) imported in function __ehhandler$??0Exception@Poco@@QAE@ABV01@@Z

完全删除.lib,as suggested here:与上述相同的错误

我也尝试了以上的一些组合,都无济于事。

任何线索将不胜感激。但同样有用的是任何指向有助于调试(或了解)这些类型问题的资源的指针。

【问题讨论】:

【参考方案1】:

您必须在命令行上定义 POCO_STATIC 并与 PocoFoundationmt 和 PocoNetmt.lib 链接:

C:\test>cl /MD /WX /nologo /EHsc /DPOCO_STATIC /DUNICODE /D_UNICODE /I..\poco\Foundation\include /I ..\poco\Net\include /c exp.cpp

exp.cpp

C:\test>link /libpath:..\poco\lib /WX /nologo exp.obj PocoNetmt.lib PocoFoundationmt.lib

[更新] 如果使用/DPOCO_STATIC 编译,则无需在链接器命令行上指定 POCO 库。头文件包含#pragma comment(lib, "PocoXXXmt.lib") 语句,应确保链接所有必要的库。

如果您不使用/DPOCO_STATIC 进行编译,则会自动链接DLL 导入库。 [/更新]

【讨论】:

谢谢。 POCO_STATIC 是关键。我强烈建议在高级文档和自述文件中的某个地方使这个晦涩难懂的咒语更加突出。在谷歌上搜索 POCO_STATIC 时,唯一的引用是在博客文章中。【参考方案2】:

听起来问题在于PocoNet.lib 文件是 poco.dll 的导入库。所以它解析的外部变量是DLL。

您需要为 Poco 找到或构建一个静态库(如果可能)。

【讨论】:

但是我该如何验证呢?我提到我最终找到并切换到了PocoNetmt.lib;这就是开始给我链接错误的原因。 (Poco 构建系统默认生成共享库和静态库。)【参考方案3】:

您的代码及其所有依赖项需要 /MT 才能静态链接到 MSVC 运行时 (MSVCP90.dll/MSVCR90.dll)。

那是因为 PocoNetmt.lib 似乎是用 /MT 构建的。

如果使用 /MT 你仍然得到 msvcprt.lib,打开 /verbose 并找出哪个其他库拖动它。然后重新编译/找到它的静态构建。

另一种选择是找到使用 /MD 构建的静态 PocoNet 库(因此您静态链接到它,但动态链接到运行时)并将所有内容切换到 /MD。

编辑: 当 Poco dll 与不影响您的 /MT 链接时。但既然你想摆脱它,你(和你所有的 other 依赖项)将不得不使用相同的 /MT 标志。

【讨论】:

我刚从 Poco 邮件列表中收到一份回复,告诉我,虽然 PocoNetmt.lib 确实用于静态链接,但 Poco 库本身都是用 /MT 构建的,所以我仍然需要与标准运行时库动态链接 - 这很好。我只是不想随身携带 PocoNet.dll,这就是我不知道该怎么做。 /MT 表示您链接到运行时 dll。 /MD 表示你愿意。并且此标志在您链接到的所有库中必须相同。 啊,抱歉。我知道这一点,我的意思是写“都是用 /MD 构建的”。【参考方案4】:

POCO >= 1.4.0 支持静态与静态运行时(仍然是静态与动态运行时)

https://raw.github.com/pocoproject/poco/poco-1.4.5/CHANGELOG (搜索“debug_static_mt”)

在包含 poco 标头时不要忘记定义 POCO_STATIC

【讨论】:

以上是关于如何使用 link.exe 进行静态链接的主要内容,如果未能解决你的问题,请参考以下文章

易语言无法定位链接器!请检查 tools\link.ini 中的配置是不是正确。

如何获取 Expo 静态深度链接进行开发?

小白求教静态编译提示无法定位连接器怎么搞

如何在mingw中进行libwinpthread-1.dll的静态链接?

如何静态链接到 libstdc++.喜欢升级的GCC的朋友快来看看

如何使用cmake生成基于静态库的动态链接库