CMake:如何生成“尽可能静态”的二进制文件
我想控制在 CMake 中找到/与我的二进制文件链接的库的类型。最终目标是生成“尽可能静态”的二进制文件,即静态链接到每个具有可用静态版本的库。这很重要,因为可以在测试期间实现二进制文件跨不同系统的可移植性。
ATM 这似乎很难实现,因为 FindXXX.cmake 包,或者更准确地说,只要静态和动态都可用,find_library 命令总是会选取动态库。
关于如何实现此功能的提示(最好以优雅的方式)将非常受欢迎!
I would like to have control over the type of the libraries that get found/linked with my binaries in CMake. The final goal is, to generate binaries "as static as possible" that is to link statically against every library that does have a static version available. This is important as would enable portability of binaries across different systems during testing.
ATM this seems to be quite difficult to achieve as the FindXXX.cmake packages, or more precisely the find_library command always picks up the dynamic libraries whenever both static and dynamic are available.
Tips on how to implement this functionality - preferably in an elegant way - would be very welcome!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我做了一些调查,虽然我找不到令人满意的解决方案,但我确实找到了一个一半的解决方案。
静态构建的问题归结为三件事:
构建和链接项目的内部库。
非常简单,只需打开
BUILD_SHARED_LIBS
开关OFF
即可。查找外部库的静态版本。
唯一的方法似乎是设置
CMAKE_FIND_LIBRARY_SUFFIXES
以包含所需的文件后缀(这是一个优先级列表)。这个解决方案相当“肮脏”,并且非常违背 CMake 的跨平台愿望。恕我直言,这应该由 CMake 在幕后处理,但据我了解,由于 Windows 上的“.lib”混淆,CMake 开发人员似乎更喜欢当前的实现。
静态链接系统库。
CMake 提供了一个选项
LINK_SEARCH_END_STATIC
基于文档:“结束链接行,以便使用静态系统库。”人们会想,就是这样,问题解决了。然而,目前的实施似乎并不能胜任这项任务。如果打开该选项,CMake 会生成一个隐式链接器调用,其参数列表以传递给链接器的选项结尾,包括
-Wl,-Bstatic
。然而,这还不够。仅指示链接器静态链接会导致错误,在我的例子中:/usr/bin/ld: 找不到 -lgcc_s
。缺少的是告诉 gcc 我们需要通过-static
参数进行静态链接,该参数不是由 CMake 生成的链接器调用。我认为这是一个错误,但我还没有得到开发人员的确认。最后,我认为所有这些都可以而且应该由 CMake 在幕后完成,毕竟它并没有那么复杂,只是在 Windows 上是不可能的 - 如果这也算复杂的话......
I did some investigation and although I could not find a satisfying solution to the problem, I did find a half-solution.
The problem of static builds boils down to 3 things:
Building and linking the project's internal libraries.
Pretty simple, one just has to flip the
BUILD_SHARED_LIBS
switchOFF
.Finding static versions of external libraries.
The only way seems to be setting
CMAKE_FIND_LIBRARY_SUFFIXES
to contain the desired file suffix(es) (it's a priority list).This solution is quite a "dirty" one and very much against CMake's cross-platform aspirations. IMHO this should be handled behind the scenes by CMake, but as far as I understood, because of the ".lib" confusion on Windows, it seems that the CMake developers prefer the current implementation.
Linking statically against system libraries.
CMake provides an option
LINK_SEARCH_END_STATIC
which based on the documentation: "End a link line such that static system libraries are used."One would think, this is it, the problem is solved. However, it seems that the current implementation is not up to the task. If the option is turned on, CMake generates a implicit linker call with an argument list that ends with the options passed to the linker, including
-Wl,-Bstatic
. However, this is not enough. Only instructing the linker to link statically results in an error, in my case:/usr/bin/ld: cannot find -lgcc_s
. What is missing is telling gcc as well that we need static linking through the-static
argument which is not generated to the linker call by CMake. I think this is a bug, but I haven't managed to get a confirmation from the developers yet.Finally, I think all this could and should be done by CMake behind the scenes, after all it's not so complicated, except that it's impossible on Windows - if that count as complicated...
制作精良的 FindXXX.cmake 文件将包含一些与此相关的内容。如果查看 FindBoost.cmake,则可以设置 Boost_USE_STATIC_LIBS 变量来控制是否查找静态库或共享库。不幸的是,大多数软件包没有实现这一点。
如果模块使用 find_library 命令(大多数都是如此),那么您可以通过 CMAKE_FIND_LIBRARY_SUFFIXES 变量。以下是 FindBoost.cmake 中用于使用此功能的相关 CMake 代码:
您可以将其放在调用 find_package 之前,或者更好的是,您可以修改 .cmake 文件本身并回馈社区。
对于我在项目中使用的 .cmake 文件,我将它们全部保存在源代码管理中自己的文件夹中。我这样做是因为我发现某些库的正确 .cmake 文件不一致,并且保留我自己的副本允许我进行修改并确保签出代码的每个人都拥有相同的构建系统文件。
A well made FindXXX.cmake file will include something for this. If you look in FindBoost.cmake, you can set the Boost_USE_STATIC_LIBS variable to control whether or not it finds static or shared libraries. Unfortunately, a majority of packages do not implement this.
If a module uses the find_library command (most do), then you can change CMake's behavior through CMAKE_FIND_LIBRARY_SUFFIXES variable. Here's the relevant CMake code from FindBoost.cmake to use this:
You can either put this before calling find_package, or, better, you can modify the .cmake files themselves and contribute back to the community.
For the .cmake files I use in my project, I keep all of them in their own folder within source control. I did this because I found that having the correct .cmake file for some libraries was inconsistent and keeping my own copy allowed me to make modifications and ensure that everyone who checked out the code would have the same build system files.