【问题标题】:CMake: include library dependencies in a static libraryCMake:在静态库中包含库依赖项
【发布时间】:2012-12-21 09:41:59
【问题描述】:

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

但我在 CMake 中找不到如何操作。您可以通过 CMake 设置此标志,还是以其他方式获得相同的结果?我已经尝试过 target_link_libraries(...) 和 add_dependencies(...),但 CMake 似乎只是忽略了静态库的这一行。

【问题讨论】:

  • 您是否有需要链接的库的静态版本?还是您只有共享版本?
  • 那么当你说它没有将它们包含在你的静态库中时,它是否试图将你的静态库与其他共享库链接起来?
  • 我只有静态库,我只尝试构建一个静态库,所以没有发生链接。当第三方想要使用我的库并且还必须链接到许多其他东西时,问题就来了

标签: c++ cmake


【解决方案1】:

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

考虑两个源文件:

test1.c:

 int hi()
 {
   return 0;
 }

test2.c:

int bye()
{
  return 1;
}

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>)

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


基于 How do I set the options for CMAKE_AR?,看起来更好的方法是:

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

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

【讨论】:

  • 谢谢,在Windows上对应的做法是添加自定义命令“lib.exe /OUT:combined.lib 1.lib 2.lib”
  • 在使用了一段时间后,我注意到“ar”命令非常粗略,并且生成的组合库至少在某些版本的 gcc 中不起作用。我认为我们最好不要尝试以这种方式静态链接。
  • 对我来说,只有首先描述的 add_custom_target 命令有效。
  • 为了使其真正独立于平台,文件名需要如下:${CMAKE_STATIC_LIBRARY_PREFIX}combined${CMAKE_STATIC_LIBRARY_SUFFIX}
【解决方案2】:

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

滥用 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}
)

请注意,到目前为止,此解决方案适用于 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..."
)

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

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

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

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

就我而言,它并不完全令人满意,因为mainexec 必须知道combinedLib,尽管它希望所有依赖关系都由target_link_libraries 调用处理。

耦合较少的替代解决方案

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

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)

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

便携式 CMake 解决方案

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

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

target_link_libraries(mainexec combinedLib)

就是这样!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 2023-03-18
    相关资源
    最近更新 更多