cmake:在静态库中包含库依赖项

Rol*_*lle 27 c++ cmake

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

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

tpg*_*114 16

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

考虑两个源文件:

test1.c:

 int hi()
 {
   return 0;
 }
Run Code Online (Sandbox Code Playgroud)

test2.c中:

int bye()
{
  return 1;
}
Run Code Online (Sandbox Code Playgroud)

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>)
Run Code Online (Sandbox Code Playgroud)

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


编辑:

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

add_custom_target(combined ALL
   COMMAND ${CMAKE_CXX_ARCHIVE_CREATE} libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢,在Windows上执行此操作的相应方法是添加自定义命令"lib.exe /OUT:combined.lib 1.lib 2.lib" (3认同)
  • 为了使其真正独立于平台,文件名需要如下:`${CMAKE_STATIC_LIBRARY_PREFIX}combined${CMAKE_STATIC_LIBRARY_SUFFIX}` (2认同)

Rol*_*zin 9

我想通过提供我的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}
)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

target_link_libraries(mainexec ${LIBNAME})
add_dependencies(mainexec combinedLib)
Run Code Online (Sandbox Code Playgroud)

在我的情况下,它并不完全令人满意,因为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)
Run Code Online (Sandbox Code Playgroud)

如果您打算模块化整个添加GLOBALSTATIC IMPORTED,使导入的目标全局可见.

便携式CMake解决方案

使用当前的CMake版本,CMake提供对传递依赖项和接口库的完全支持.然后,接口库可以与其他库"链接",并且该接口库可以反过来"链接".为什么引号?虽然这很好用,但实际上并没有创建一个物理的组合库,而是创建了一组"子库"的别名.这仍然是我们最终需要的解决方案,这就是为什么我想在这里添加它.

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

target_link_libraries(mainexec combinedLib)
Run Code Online (Sandbox Code Playgroud)

而已!