在CMake中重叠库之间的依赖关系

时间:2012-04-04 13:54:56

标签: cmake

让我们说以下目录结构:

projects
   |
   +--lib1
   |   |
   |   +-CMakeFiles.txt
   |
   +--lib2
   |   |
   |   +-CMakeFiles.txt
   |
   +--test
       |
       +-CMakeFiles.txt

LIB1 / CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)

add_library(lib1 STATIC lib1.cpp)

LIB2 / CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)

add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)

测试/ CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)
project(test)

add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1)
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)

add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)

即。 lib2取决于lib1test取决于它们。 (我知道技术上静态的图书馆没有"链接",但这只是一个例子。)

问题在于,使用当前设置,lib1编译两次 - 第一次在" test"构建目录,第二次在" test / build_directory / lib2 / build_directory"内。我想避免这种情况。

我希望能够将lib1,lib2或它们两者(使用add_subdirectory)的依赖性添加到位于其他位置的任何项目。所以移动CMakeFiles不是一个选择。我也想避免多次编译任何库。

我该怎么做?

cmake-2.8.4 winxp sp3

- EDIT-- 顶级cmakelists不是一个选项,因为我想保持干净的顶级目录,并能够将库包含在可以位于其他地方的其他项目中。因为它是windows,我不能在全系统安装软件包" - 我不想失去动态切换编译器的能力。使用不同编译器构建的实用程序库将使用不同的C运行时库/ ABI,因此将不兼容。

3 个答案:

答案 0 :(得分:12)

另一个解决方案是在子目录-CMakeLists.txt的顶部添加一个防护:

if(TARGET targetname)
    return()
endif(TARGET targetname)

这将导致cmake在第二次添加子目录时不执行任何操作(当然,如果在该文件中定义了targetname)。

这将导致lib beeing构建在构建/树中的任意位置(取决于首先添加它的模块),但它将只构建一次并在任何地方链接。

在您的示例中,您将添加

if(TARGET lib1)
    return()
endif(TARGET lib1)

位于lib1 / CMakeFiles.txt

的顶部

答案 1 :(得分:4)

使用CMake,库依赖项是可传递的,因此您不应在add_subdirectory中调用test/CMakeFiles.txt两次(也不需要将lib1列为test的依赖项因为它已经是lib2的依赖。

所以你可以将test的CMakeFiles.txt修改为:

cmake_minimum_required(VERSION 2.8.7)  # Prefer the most current version possible
project(test)

add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2)

add_executable(test main.cpp)
target_link_libraries(test lib2)

此外,您应该从非项目CMakeFiles.txt文件(lib文件)中删除cmake_minimum_required次调用。有关详细信息,请运行:

cmake --help-policy CMP0000


如果添加类似的test2子目录和项目(取决于lib1lib2),此设置仍将导致重新编译所有库。如果你真的不想在projects/中拥有顶级的CMakeFiles.txt,那么你就会被你正在做的事情所困扰,或者你可以使用export或{{1命令。

install会创建一个文件,该文件可能由其他项目export组成,并将目标导入到调用include的项目中。

include可以将库安装到另一个公共子目录install。根据您的源目录结构,这可能只有使目标库API头可用于依赖项目。

但是,这两个选项都需要重建(并安装)依赖库项目(如果它们被修改),而当前设置包括项目中的所有依赖目标,因此对依赖库中的源文件进行任何更改会导致projects/目标过期。

有关testexport的详细信息,请运行:

install

答案 2 :(得分:0)

也许在项目目录中添加顶级CMakeLists.txt。类似的东西:

project( YourProjects )

add_subdirectory( lib1 )
add_subdirectory( lib2 )
add_subdirectory( test )

这应该足够了,并且会在顶级build-dir中为您提供解决方案文件或makefile。然后,您应该从lib1和lib2项目中删除add_subdirectory( ../lib1 ...,而只是链接到它们。在编译测试时,CMake将知道如何找到lib1和lib2。

即。在lib2中:

project( lib2) 
add_library(lib2 STATIC lib2.cpp)
target_link_libraries(lib2 lib1)

并且在测试中:

project( test )
add_executable(test main.cpp)
target_link_libraries(test lib1 lib2)

添加了奖励:您将获得用于在lib2目录中构建lib2(带有依赖的lib1)的makefile / solutionfiles ...