使用 C 接口将 MinGW 库链接到 MSVC 应用程序

Linking a MinGW library to a MSVC app with a C interface

我正在尝试 link 到 OpenAL soft library as compiled with the Media Autobuild Suite,但我从 Visual Studio 收到以下错误:

libopenal.a(source.cpp.o) : fatal error LNK1143: invalid or corrupt file: no symbol for COMDAT section 0xA

我的应用程序是在 C++ 中直接在 Visual Studio 2019 中编译的(但是,使用 VS2017 工具集)。 OpenAL soft 是用 C++ 编写的,但暴露了一个 C 接口,MAB Suite 使用 MinGW/gcc 编译并生成一个 libopenal.a 静态库文件。

我从 From MinGW static library (.a) to Visual Studio static library (.lib) and How to use libraries compiled with MingW in MSVC? 等多个其他问题中了解到,使用不同编译器编译的 object 文件通常 由于名称原因与 C++ 兼容mangling,但通常 与 C linkage 兼容。因为 C 不使用名称修改,并且因为 ABI(通常)OS-dependent,所以在同一平台上编译的具有 C 接口的库通常是兼容的。

然而,我 运行 陷入了 link 错误,即上面的 LNK1143。我已经确认包含的 headers 使用 extern "C" { 来提示 C linkage 并且两个构建的目标平台 (x64) 相同。我还按照 this answer 的建议 link 编辑到 libgcc.a,并且没有收到任何 linker 错误。

这是否意味着 C 接口通常跨编译器兼容的说法是不正确的? 或者这是它不起作用的特殊情况?如果是后者,是什么导致 linking 失败?如果我重新编译为共享库(dlls)而不是静态库(即使我仍然使用 MinGW 的 .a 文件而不是 .lib),我的运气会更好吗?

我无法为我的主应用程序从 MSVC 更改编译器。我打算在未来使用更多来自 MAB Suite 的库,所以如果可能的话,我更愿意继续使用 MinGW 来处理这些依赖项,因为我不想手动重新编译所有 70 多个库。

感谢任何帮助。提前致谢。

混合编译器很棘手,容易出现问题。

在一些非常简单的情况下它可能会起作用,但肯定有很多情况下您会 运行 遇到问题,例如:

  • 如果不同的组件使用不同的运行时间库
  • 如果内存管理是混合的(例如忘记在 MSVC 中使用 free() 在 MinGW 中释放分配给 malloc() 的内存)
  • 在 C++ 中使用异常处理时

我的建议是使用同一个编译器(甚至是同一个版本的编译器)。

特别是在您的情况下 OpenAL 可以使用 MinGW-w64 构建。所以也许你应该研究一下,而不是从网上下载一些预构建的版本。

或者 - 更简单一些 - 使用 MSYS2 并使用它的 pacman 包管理器来获得它自己的 OpenAL MinGW-w64 版本。

我找到了适合我的方法,所以我会分享。

我无法像最初尝试的那样在编译器之间 link 静态库。我的理解是,保存在库中以允许 link 时间代码生成的额外信息是特定于编译器的。 概述了代码不兼容的几个可能原因。

但是,我能够 link 共享库,只需几个额外的步骤。

使用相同的套件(参见问题),我编译为共享并得到 libopenal.dlllibopenal.dll.alibopenal.def。在我的例子中,.def 文件是由套件生成的。根据 this answer,您可以使用 gcc 使用以下命令生成 .def 文件:

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

尝试从 link 到 libopenal.dll.a 仍然给了我错误(我不知道确切原因,我已经丢弃了日志。)我所做的是生成一个 .lib 文件从 .def 文件。在Visual Studio的内置终端中:

lib /machine:x64 /def:libopenal.def

这在工作目录中生成了一个 libopenal.lib 文件。链接到此文件非常有效,我能够在运行时成功加载 dll。

我已经用套件中的许多其他 MinGW 编译库测试了相同的方法,包括 libavformatlibavcodeclibavutillibavdeviceswresample,和 swscale,到目前为止,它们都有效。

有点复杂,但它似乎对我来说效果很好,所以我希望这对遇到同样问题的其他人有所帮助。