如何在 MSVC 中使用使用 MingW 编译的库?

Posted

技术标签:

【中文标题】如何在 MSVC 中使用使用 MingW 编译的库?【英文标题】:How to use libraries compiled with MingW in MSVC? 【发布时间】:2010-03-27 15:11:58 【问题描述】:

我已经用 MingW/MSYS 编译了几个库...生成的静态库总是 .a 文件。 当我尝试将库与 MSVC 项目链接时,Visual Studio 会抛出“未解析的外部符号”......这意味着 .a 静态库与 MS C++ 链接器不兼容。我认为它必须转换为与 MSVC 兼容的 .lib 文件。

.a 和 .lib 都只是 .o 或 .obj 文件的 AR 存档,那么有什么方法可以在 MSVC 项目中使用 MingW 编译的库吗?还是我必须在一个编译器/链接器中编译/链接所有内容 - 仅限 MSVC/仅限 MingW? 据说 MingW 编译器与 MSVC 兼容。

我阅读了一些关于这个主题的主题,但他们大多说将文件重命名为 .lib 应该可以完成工作,但不幸的是它对我不起作用。

我试图链接的库是用 C 编写的。

MSVC 链接器抛出如下错误:

error LNK2019: unresolved external symbol "int __cdecl openssl_call(struct ssl_State *,int,int,int)" (?openssl_call@@YAHPAUssl_State@@HHH@Z) referenced in function _main MyAPP.obj

...还有 4 个相同的错误涉及从我的应用调用的其他函数。

感谢您的建议。

【问题讨论】:

你不能在 MSVC 上编译所有东西吗? “.a 和 .lib 只是 .o 或 .obj 文件的 AR 存档”您确定 msvc 的静态 .lib 文件就像 .a "ar" 存档吗? 看起来这个问题(和答案)是特定于 C 而不是 C++ ......你能确认一下吗? 【参考方案1】:

基于您在评论中输入的这个错误:

错误 LNK2019:未解决的外部 符号“int __cdecl openssl_call(结构 ssl_State *,int,int,int)" (?openssl_call@@YAHPAUssl_State@@HHH@Z) 在函数 _main MyAPP.obj 中引用 所有其他 4 个错误仅与 其他函数名

尝试将extern "C" 放在您的openssl 包含文件周围。例如:

extern "C" 
include "openssl.h"

使用extern "C" 将指示编译器函数正在使用C 链接,而不是C++,这将阻止它对函数执行name mangling。所以它会在库中寻找函数 openssl_call 而不是 ?openssl_call@@YAHPAUssl_State@@HHH@。

【讨论】:

这当然是一个可能的解决方案,但如果是真的,我很惊讶 SSL 自己不这样做 - 也许作者讨厌 C++ :-) @anon OpenSSL 是 C 库,extern "C" 是 C++ 语法。 他说他的项目是用C写的。是否保证使用其中一个编译的库可以与另一个一起使用?例如,静态库怎么样?【参考方案2】:

这些库是兼容的,但前提是您提供了 C 接口。 MSVC 和 g++ 使用不同的名称修饰方案,因此您无法轻松地将使用其中一个创建的 C++ 代码与另一个创建的代码链接起来。

【讨论】:

那么我应该怎么做才能将MingW编译的lib与MSVC编译的可执行文件成功链接? 我链接库的应用程序是用 C++ 编写的,被链接的库是 C(它的 openssl、zlib 和 xerces) @NumberFour 好的,请通过将它们编辑到您的问题中来发布您遇到的一些(三个或四个)链接器错误。目前尚不清楚您是否有损坏问题或其他问题。 error LNK2019: 函数 _main MyAPP.obj 中引用的未解析的外部符号“int __cdecl openssl_call(struct ssl_State *,int,int,int)”(?openssl_call@@YAHPAUssl_State@@HHH@Z)其他 4 个错误仅与其他函数名称相同 @NumberFour 你能按照我的要求做,通过编辑你的问题而不是发表评论来发布所有错误吗?【参考方案3】:

我遇到了在 MSVC 中使用 mingw 编译的 dll 的相同情况。我使用以下工具使其工作: 1)像这样使用gcc:

gcc -shared -o your_dll.dll your_dll_src.c -Wl,--output-def,your_dll.def

粗体表示 gcc 将生成一个 *def 文件,该文件为您导出的项目编写脚本。然后您需要使用与 MSVC 一起分发的 lib.exe,示例如下:

lib /def:your_dll.def

然后,就会有一个your_dll.lib 文件,来自lib.exe。(假设you_dll.dll 与your_dll.def 位于同一目录)。

目前,我可以在我的 MSVC 项目中使用 *.lib 并正确链接 dll,但出现运行时错误。无论如何,这样的作品使您的链接可行。

【讨论】:

.dll 应该与 .def 位于同一目录的原因是因为 .def 只是用于转换的元信息。剩下的问题是:如果库没有 C 样式接口,使用 lib.exe 进行转换是否也有效?这个答案提到了运行时错误这一事实意味着该实用程序相当无用......【参考方案4】:

简介

使用不同编译器创建的目标文件和静态库,或者甚至使用同一编译器的显着不同版本创建的目标文件和静态库通常无法链接在一起。此问题并非特定于 MinGW:许多其他编译器相互不兼容。如果可以的话,使用相同版本的相同编译器从源代码构建所有内容。

Dll 略有不同。有时您可以将使用一种编译器构建的 DLL 链接到使用另一种编译器编译的应用程序。如果 DLL 是用 C 编写的,即使应用程序是用 C++ 编写的,这也很有效。例如,MinGW C++ 程序通常链接到 Windows 提供的 C 运行时库。用 C++ 编写的 DLL 也可以工作,只要您仅通过用 extern "C" 声明的 C 接口与它们通信。否则,您可能会收到链接器错误,因为不同的编译器会以不同的方式处理 C++ 名称。

为什么不同的编译器可能无法互操作

有时人们想知道为什么编译器编写者不只是使用相同的名称修饰方案。这可能会使链接成功,但很可能会给您一个在调用 DLL 时崩溃的程序。真正的链接兼容性需要一个通用的应用程序二进制接口,而名称修改只是众多考虑因素之一。这是部分列表:--

http://ou800doc.caldera.com/SDK_porting/binary_cplusplus_compat.html 根据此页面,一个编译器提供 3200 种不同的 ABI:http://www.boost.org/libs/config/config.htm#source 根据 Stroustrup(ARM,7.2.1c,第 122 页):

如果同一系统的两个 C++ 实现使用不同的调用 序列,或以其他方式与链接不兼容,它将是 使用相同的类型签名编码是不明智的。

实施者传统上故意使用不同的名称修改方案,认为在链接时“只说不”比让一些简单的代码工作并让问题在运行时出现要好。

尽管 GNU g++ 现在可以链接 MSVC C++ 库,并且可以生成与 MSVC++ 兼容的库/DLL,但这并不意味着由于 C++ 的动态特性,它们将能够在运行时工作。一些可能的原因是:--

简单的名称修改问题,可以通过显式 .def 文件规避。 需要正确编译器选项(-mms-bitfields,...)的不同结构对齐问题。 底层异常和内存模型的根本冲突:--
    MSVC DLL 中的 new/delete 或 malloc/free 无法与 Cygwin newlib new/delete 或 malloc/free 协作。根本无法释放在函数中使用不同的 new/malloc 分配的空间。 由 MSVC DLL 引发的异常不会被 Cygwin 可执行文件捕获,反之亦然。 慢速 GNU SJLJ 异常模型(用于 GCC-3.x 及更早版本)与 MSVC++ 模型兼容,但新的 DWARF2 模型(将由 GCC-4.x 使用)将是不兼容。

参考:http://www.mingw.org/wiki/Interoperability_of_Libraries_Created_by_Different_Compiler_Brands

【讨论】:

以上是关于如何在 MSVC 中使用使用 MingW 编译的库?的主要内容,如果未能解决你的问题,请参考以下文章

vs 编译库文件 Qt编译库文件

如何在 Qt creator 中更改/配置所需的编译器?即在 MSVC/Mingw 或 g++/clang++ 之间切换

使用 gcc 和 msvc 工具集生成的库

从 MinGW 调用 MSVC DLL 函数

使用MinGW编译Qt Creator

在啥情况下为 Qt MinGW 或 MSVC 选择啥编译器?