C++ CMake:在静态库中包含库依赖项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14199708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:06:50  来源:igfitidea点击:

CMake: include library dependencies in a static library

c++cmake

提问by Rolle

I am building a staticlibrary in CMake, which is dependent on many other static libraries. I would like them all to be included in the output .lib/.a file, so I can just ship a big lib file to customers. In Visual Studio 2010 there is an option, "Link Library Dependencies", which does exactly this.

我正在CMake 中构建一个静态库,它依赖于许多其他静态库。我希望它们都包含在输出 .lib/.a 文件中,这样我就可以将一个大的 lib 文件发送给客户。在 Visual Studio 2010 中有一个选项"Link Library Dependencies",它就是这样做的。

But I can't find how to do it in CMake. Can you set this flag via CMake, or get the same result some other way? I have tried target_link_libraries(...) and also add_dependencies(...), but CMake seems to simply ignore this line for static libraries.

但我找不到如何在 CMake 中做到这一点。你能通过 CMake 设置这个标志,或者以其他方式获得相同的结果吗?我已经尝试过 target_link_libraries(...) 和 add_dependencies(...),但 CMake 似乎只是忽略了静态库的这一行。

采纳答案by tpg2114

Okay, so I have a solution. First it's important to recognize that static libraries do not link other static libraries into the code. A combined library must be created, which on Linux can be done with ar. See Linking static libraries to other static librariesfor more info there.

好的,所以我有一个解决方案。首先,重要的是要认识到静态库不会将其他静态库链接到代码中。必须创建一个组合库,在 Linux 上可以使用ar. 有关更多信息,请参阅将静态库链接到其他静态库

Consider two source files:

考虑两个源文件:

test1.c:

测试1.c:

 int hi()
 {
   return 0;
 }

test2.c:

测试2.c:

int bye()
{
  return 1;
}

The CMakeLists.txtfile is to create two libraries and then create a combined library looks like:

CMakeLists.txt文件是创建两个库然后创建一个组合库看起来像:

project(test)

    add_library(lib1 STATIC test1.c)
    add_library(lib2 STATIC test2.c)

    add_custom_target(combined ALL
      COMMAND ${CMAKE_AR} rc libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)

The options to the arcommand are platform-dependent in this case, although the CMAKE_ARvariable is platform-independent. I will poke around to see if there is a more general way to do this, but this approach will work on systems that use ar.

ar在这种情况下,命令的选项与平台相关,尽管CMAKE_AR变量与平台无关。我会四处看看是否有更通用的方法来做到这一点,但这种方法适用于使用ar.



Based on How do I set the options for CMAKE_AR?, it looks like the better way to do this would be:

基于如何设置 CMAKE_AR 的选项?,看起来更好的方法是:

add_custom_target(combined ALL
   COMMAND ${CMAKE_CXX_ARCHIVE_CREATE} libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)

This should be platform-independent, because this is the command structure used to create archives internally by CMake. Provided of course the only options you want to pass to your archive command are rcas these are hardwired into CMake for the arcommand.

这应该是平台无关的,因为这是 CMake 用于在内部创建档案的命令结构。当然,您要传递给存档命令的唯一选项是rc因为这些选项已硬连线到 CMake 中以用于ar命令。

回答by Roland Sarrazin

I'd like to enhance the other solutions by providing my CMakeLists.txtfile that actually works also in terms of building dependencies.

我想通过提供我的CMakeLists.txt文件来增强其他解决方案,该文件在构建依赖项方面也确实有效。

Solution misusing CMake

滥用CMake的解决方案

cmake_minimum_required(VERSION 2.8)

add_library(lib1 test1.cpp)
add_library(lib2 test2.cpp)
include_directories(${CMAKE_CURRENT_DIR})
add_executable(mainexec main.cpp)
target_link_libraries(mainexec combinedLib)  # Important to place before add_custom_target

set(LIBNAME "combinedLib.lib")

add_custom_command(
    OUTPUT ${LIBNAME}
    COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
    DEPENDS lib1 lib2
    COMMENT "Combining libs..."
)

add_custom_target(combinedLib
    DEPENDS ${LIBNAME}
)

Note that this solution works so far with Visual Studio but I guess it can be made multi-platform compliant. I can imagine that the following version might work for Unix-based platforms:

请注意,此解决方案目前适用于 Visual Studio,但我想它可以兼容多平台。我可以想象以下版本可能适用于基于 Unix 的平台:

set(LIBNAME "libCombinedLib.a")

add_custom_command(
    OUTPUT ${LIBNAME}
    COMMAND ar -rcT ${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
    DEPENDS lib1 lib2
    COMMENT "Combining libs..."
)

Note that these solutions somehow misuse CMake as it would complain about a target of type UTILITY (instead of STATIC or SHARED) if you place the target_link_librariescall after the add_custom_targetdeclaration.

请注意,这些解决方案会以某种方式滥用 CMake,因为如果您target_link_librariesadd_custom_target声明之后进行调用,它会抱怨类型为 UTILITY(而不是 STATIC 或 SHARED)的目标。

CMake target-declaration-compliant solution

符合 CMake 目标声明的解决方案

To make it CMake compliant, you can replace the `target_link_libraries' call by

为了使其符合 CMake,您可以将 `target_link_libraries' 调用替换为

target_link_libraries(mainexec ${LIBNAME})
add_dependencies(mainexec combinedLib)

In my case it is not entirely satisfactory because mainexechas to know about combinedLibalthough it expects all dependencies to be handled by the target_link_librariescall.

在我的情况下,它并不完全令人满意,因为尽管它期望所有依赖项都由调用处理,但它mainexec必须知道。combinedLibtarget_link_libraries

Alternative solution with less coupling

耦合较少的替代解决方案

Looking a bit further towards imported targets I eventually found a solution that solves my last problem:

进一步研究导入的目标,我最终找到了解决我最后一个问题的解决方案:

cmake_minimum_required(VERSION 2.8)

add_library(lib1 test1.cpp)
add_library(lib2 test2.cpp)
include_directories(${CMAKE_CURRENT_DIR})
add_executable(mainexec main.cpp)

set(LIBNAME "combinedLib.lib")

add_custom_command(
    OUTPUT ${LIBNAME}
    COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
    DEPENDS lib1 lib2
    COMMENT "Combining libs..."
)

add_custom_target(combinedLibGenerator
    DEPENDS ${LIBNAME}
)

add_library(combinedLib STATIC IMPORTED)
set_property(TARGET combinedLib PROPERTY IMPORTED_LOCATION ${LIBNAME})
add_dependencies(combinedLib combinedLibGenerator)

target_link_libraries(mainexec combinedLib)

If you intend to modularize the whole add GLOBALafter STATIC IMPORTEDto make the imported target globally visible.

如果您打算模块化整个添加GLOBAL之后STATIC IMPORTED使导入的目标全局可见。

Portable CMake solution

便携式 CMake 解决方案

With the current CMake versions CMake provides full support for transitive dependencies and interface libraries. An interface library can then "link" against other libraries and this interface library can, in turn, be "linked" against. Why quotation marks? While this works good, this actually doesn't create a physical, combined library but rather creates a kind of an alias to the set of "sub-libs". Still this was the solution we eventually needed, which is why I wanted to add it here.

在当前的 CMake 版本中,CMake 提供对可传递依赖项和接口库的全面支持。一个接口库然后可以“链接”到其他库,而这个接口库又可以“链接”到其他库。为什么要加引号?虽然这很好用,但这实际上并没有创建一个物理的、组合的库,而是创建了一种“子库”集的别名。这仍然是我们最终需要的解决方案,这就是我想在这里添加它的原因。

add_library(combinedLib INTERFACE)
target_link_libraries(combinedLib INTERFACE lib1 lib2)

target_link_libraries(mainexec combinedLib)

That's it!

就是这样!