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

18

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

我使用以下命令构建我的程序:

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

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

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

我尝试指定/MT,但似乎并没有什么改变;我的应用仍然需要Poco DLLs。(我也怀疑/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,就像这里建议的那样: 仍然出现与上述相同的错误

我还尝试了一些组合,但都没有成功。

任何线索都将非常感激。但同样有用的是指向对调试(或学习)此类问题有用的资源的指针。

4个回答

15

你需要在命令行中定义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导入库。 [/更新]


2
谢谢。POCO_STATIC是关键。我强烈建议在高级文档和README中更突出地展示这个晦涩的咒语。当搜索POCO_STATIC时,唯一的参考资料都在博客文章中。 - Yang

5

看起来问题在于 PocoNet.lib 文件是 poco.dll 的导入库。因此,它解析的外部函数是 DLL 中的。

如果可能的话,您需要查找或构建 Poco 的静态库。


但是我该如何验证这一点呢?我提到我最终找到并切换到了PocoNetmt.lib;这就是开始出现链接错误的原因。(Poco构建系统默认生成共享库和静态库。) - Yang

0

你需要在你的代码及其所有依赖项中使用 /MT 以静态链接到 MSVC 运行时(MSVCP90.dll/MSVCR90.dll)。

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

如果你仍然得到 msvcprt.lib,即使使用 /MT,请打开 /verbose 并找出哪个其他库将其拖动。然后重新编译/查找该库的静态版本。

另一种选择是找到使用 /MD 构建的静态 PocoNet lib(这样你可以静态链接到它,但动态链接到运行时),并将所有内容切换到 /MD。

编辑: 当 Poco dll 链接到 /MT 时,这不会影响你。但是,由于你想要摆脱它,你(和所有其他依赖项)都必须使用相同的 /MT 标志。


我刚从Poco邮件列表中得到了一个回复,告诉我虽然PocoNetmt.lib确实是用于静态链接的,但Poco库本身都是使用/MT构建的,因此我仍需要动态链接标准运行时库——这很好。我只是不想带着PocoNet.dll,但我不知道该怎么做。 - Yang
/MT 表示你 不会 链接到运行时 dll。/MD 表示你会链接到它们。而且这个标志必须在你链接到的所有库中保持一致。 - Eugene
抱歉,我知道这个。我的意思是写“都是用/MD构建的”。 - Yang

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接