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

24
我用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上编译所有东西吗? - the_drow
".a和.lib文件要么只是.o或.obj文件的AR存档,你确定msvc的静态.lib文件就像.a“ar”存档一样吗?" - Johan Boulé
看起来这个问题(以及答案)是针对 C 而不是 C++ 的... 你能确认一下吗? - lofidevops
4个回答

17

根据您在评论中提供的错误:

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 all other 4 errors are same only with other functions names

尝试在openssl的包含文件周围添加extern "C" 。例如:

extern "C" {
include "openssl.h"
}

使用extern "C"将告诉编译器,函数是使用 C 语言链接而不是 C++,从而防止对函数进行名称修饰。因此,它将在库中查找函数 openssl_call,而不是 ?openssl_call@@YAHPAUssl_State@@HHH@。


4
这确实是一个可能的解决方案,但如果属实,我会感到惊讶,因为SSL本身不会这样做 - 或许作者讨厌C++ :-) - anon
OpenSSL是一个C库,而extern "C"是C++语法。 - osvein
他说他的项目是用 C 写的。可以保证使用一个编译的库能够在另一个上工作吗?例如,静态库呢? - Royi

12

这些库是兼容的,但只有在提供 C 接口的情况下才能实现。MSVC 和 g++ 使用不同的名称重整方案,因此您不能轻松地将使用其中一个创建的 C++ 代码与另一个创建的代码链接起来。


2
那么,为了成功地将MingW编译的库与MSVC编译的可执行文件链接起来,我应该怎么做呢? - NumberFour
我正在链接的应用程序是用C++编写的,被链接的库是C语言编写的(它们是openssl、zlib和xerces)。 - NumberFour
@NumberFour 好的,请在问题中编辑几个(三到四个)链接器错误。仍然不清楚您是否有名称混淆问题或其他问题。 - anon
错误 LNK2019:在函数 _main MyAPP.obj 中引用了未解析的外部符号 "int __cdecl openssl_call(struct ssl_State *,int,int,int)" (?openssl_call@@YAHPAUssl_State@@HHH@Z)。其他四个错误与此相同,只是函数名称不同。 - NumberFour
@NumberFour,你能按照我的要求做吗?通过编辑你的问题来发布所有的错误信息,而不是通过评论来发布。 - anon

11

我遇到了与在MSVC中使用mingw编译的dll相同的情况。我使用以下工具使其正常工作:
1) 使用gcc命令如下:

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

加粗字指定gcc将生成一个*def文件,该文件脚本化了您导出的项目。然后,您需要使用lib.exe,它是随MSVC一起分发的,示例如下:

lib /def:your_dll.def

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

目前,我可以在我的MSVC项目中使用*.lib,并正确地链接到dll,但我得到了运行时错误。 无论如何,这种方法可以使您的链接可行。


1
.dll 应该与 .def 文件放在同一个目录下的原因是,.def 只是用于转换的元信息。问题是:如果库没有 C 风格的接口,使用 lib.exe 进行转换是否也有效?这个答案提到运行时错误的事实意味着这个工具相当无用... - jiggunjer

8

介绍

使用不同编译器创建的目标文件和静态库,甚至是使用同一编译器的显著不同版本创建的,往往不能链接在一起。这个问题并不特定于MinGW:许多其他编译器也是相互不兼容的。如果可以,请使用同一版本的同一编译器从源代码构建所有内容。

DLL略有不同。有时候你可以将一个使用其中一个编译器构建的DLL链接到使用另一个编译器编译的应用程序中。如果DLL是用C语言编写的,即使应用程序是用C ++编写的,也能够正常工作。例如,在MinGW C ++程序中,通常会链接到Windows提供的C运行时库。用C ++编写的DLL也可以工作,只要您通过声明extern "C"的C接口与它们进行通信即可。否则,由于不同的编译器以不同方式搅乱C ++名称,您可能会遇到链接器错误。

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

有时候人们想知道为什么编译器编写者不能只使用相同的名称搅拌方案。这可能使链接成功,但最有可能的结果是当您调用DLL时程序崩溃。真正的链接兼容性需要一个共同的应用二进制接口,名称搅拌只是其中一个考虑因素。以下是部分清单:--

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

实现者传统上使用故意不同的名称搅拌方案,认为在链接时间“Just say no”比让某些简单代码工作并使问题在运行时出现更好。

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

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

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


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