微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 mingw 库与 cmake 链接 问题解决办法

如何解决将 mingw 库与 cmake 链接 问题解决办法

长话短说,我将 Godot 构建系统重写为 cmake(仅 Windows 部分),主要是因为我想学习它,但是我在用 mingw 编译 Godot 时遇到了麻烦。当我试图编译它时,一开始一切都很好,直到链接最终 exe 的时候,在那里我得到了很多“未定义的引用”错误。看起来主库(核心/场景/编辑器/..)无法看到彼此的功能。 MSVC 构建工作正常,并且 scons 版本也在 mingw 下编译,所以我显然只是错过了我的 cmake 版本中的某些内容。作为测试,我尝试删除整个 cmake 脚本中的一些编译/链接选项,但没有任何改变。我真的不知道如何调试这个问题,所以如果有人能把我踢到正确的方向,我会很高兴。

解决方法

好的,我终于有时间回到这个话题了。

问题

所以基本上问题在于对 godot 库的循环依赖。我不认为这是问题所在,因为我被 MSVC 宠坏了(它不依赖于链接顺序)。此外,我尝试在一个规模小得多的测试项目中复制 mingw 中的循环依赖。该项目是一个 30 个库,每个库中有两个函数,第一个函数打印字符串,另一个调用所有 30 个库中的所有第一个函数,因此有 30 个循环依赖库。奇怪的是,项目链接没有问题,打印了30^2个字符串..

解决办法

解决方案是在所有库周围使用 -Wl,--start-group/-Wl,--end-group 链接标志。有两种方法可以做到。

第一种方法,是将所有库添加到某种列表中。这可能是全局属性,或某个目标上的属性(不仅仅是一个简单的变量),因此可以从其他子目录访问它。形成库列表后,您只需将其链接到可执行文件,如下所示

# getting all your libs from the global property..
get_property(__LIBS_LIST GLOBAL PROPERTY EXE_LIBS_LIST)
# linking all libraries to the exe..
target_link_libraries(my-exe PRIVATE -Wl,--start-group ${__LIBS_LIST} -Wl,--end-group)

这是最简单的解决方案,但要注意链接到 exe 的库的依赖关系,因为当 CMake 为您的 exe 创建链接行时,它首先列出直接链接到您的 exe 的所有库,并且只有在它放置来自直接链接的库的依赖项的库之后。基本上,如果您的目标依赖树看起来像这样: exe // 你的主要 exe 文件 - lib_A // lib A 直接链接到主exe - lib_AA // 链接到 lib_A 的 lib AA - lib_AAA // 链接到 lib_AA 的 lib AAA - lib_B // lib B 直接链接到主exe - lib_BB // 链接到 lib_B 的 lib BB - lib_BBB // 链接到 lib_BB 的 lib BBB 您的 exe 链接顺序如下所示: // 第一个库直接链接到 exe 库_A 库_B // 仅在递归初始库依赖项之后 库_AA lib_AAA lib_BB lib_BBB

这就是说,如果你将像 target_link_libraries(my-exe PRIVATE -Wl,--end-group) 这样的库链接起来,--start-group 和 --end-group 将只保护直接链接到你的 exe 的库。我没有在文档中找到这个描述,但我发现 SO question 几乎谈论相同的行为 (CMake library linking order)。此外,当我在 mingw 上对此进行测试时,lib_AA/lib_AAA/lib_BB/lib_BBB 是如何链接的并不重要,通过 PRIVATE 或通过 INTERFACE,结果是相同的。

第二种方法,是利用链接扩展的递归性来解决直接链接到 exe 的库的依赖项。从我的示例中您可以看到,lib_A (lib_AA/lib_AAA) 的依赖项没有与 lib_B (lib_BB/lib_BBB) 的依赖项混合在一起。所以基本上我们能做的就是创建 INTERFACE 库并在此之后立即连接到它 -Wl,--start-group 。然后将任意数量的库添加到它的界面并将全局库链接到您的 exe(顺序无关紧要)。最后,关闭 global-libs 库中的组

add_library(global-libs INTERFACE)
target_link_libraries(global-libs INTERFACE -Wl,--start-group)
# ...
# linking another libs,and linking global-libs to exe
# ...
target_link_libraries(global-libs INTERFACE -Wl,--end-group)

这将确保所有连接到 global-libs 的库都被 -Wl,--end-group 包围。

现在,理论上,CMake 应该自己处理循环依赖,通过在链接行中多次放置库(多少次由 LINK_INTERFACE_MULTIPLICITY 控制)。但是这种方法对我不起作用(我只是错过了一些东西......)。另外,您需要声明 cmake 目标之间的依赖关系,并且使用 -Wl,--end-group 您可以将一个特定的接口库设置为所有具有循环依赖项的库的持有者。>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。