使用 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 失败?如果我重新编译为共享库(dll
s)而不是静态库(即使我仍然使用 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.dll
、libopenal.dll.a
和 libopenal.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 编译库测试了相同的方法,包括 libavformat
、libavcodec
、libavutil
、libavdevice
、swresample
,和 swscale
,到目前为止,它们都有效。
有点复杂,但它似乎对我来说效果很好,所以我希望这对遇到同样问题的其他人有所帮助。
我正在尝试 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 失败?如果我重新编译为共享库(dll
s)而不是静态库(即使我仍然使用 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.dll
、libopenal.dll.a
和 libopenal.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 编译库测试了相同的方法,包括 libavformat
、libavcodec
、libavutil
、libavdevice
、swresample
,和 swscale
,到目前为止,它们都有效。
有点复杂,但它似乎对我来说效果很好,所以我希望这对遇到同样问题的其他人有所帮助。