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

Sig*_*erm 8 cmake

假设有以下目录结构:

projects
   |
   +--lib1
   |   |
   |   +-CMakeFiles.txt
   |
   +--lib2
   |   |
   |   +-CMakeFiles.txt
   |
   +--test
       |
       +-CMakeFiles.txt
Run Code Online (Sandbox Code Playgroud)

LIB1/CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0)

add_library(lib1 STATIC lib1.cpp)
Run Code Online (Sandbox Code Playgroud)

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

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

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,因此将不兼容.

use*_*450 13

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

if(TARGET targetname)
    return()
endif(TARGET targetname)
Run Code Online (Sandbox Code Playgroud)

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

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

在您的示例中,您将添加

if(TARGET lib1)
    return()
endif(TARGET lib1)
Run Code Online (Sandbox Code Playgroud)

在lib1/CMakeFiles.txt的顶部

  • 不幸的是,在 CMake 3.13 版本中,此解决方案不起作用。CMake 停止并显示一条错误消息,该消息指向 add_subdirectory 调用(尝试包含 subdirectory-CMakeLists.txt 文件)本身。解决方法是在 add_subdirectory 调用周围放置防护: `if (NOT TARGET lib1) add_subdirectory(lib1) endif()` (2认同)

Fra*_*ser 6

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

因此,您可以将testCMakeFiles.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)
Run Code Online (Sandbox Code Playgroud)

另外,您可能应该cmake_minimum_required从非项目CMakeFiles.txt文件(lib文件)中删除调用。有关更多信息,请运行:

cmake --help-policy CMP0000
Run Code Online (Sandbox Code Playgroud)


如果添加依赖于lib1和的类似test2子目录和项目,此设置仍将导致所有库重新编译lib2。如果您确实不想在中拥有顶级CMakeFiles.txt projects/,那么您就束手无策了,或者可以使用exportor install命令。

export会创建一个文件,该文件可以include由其他项目进行打包,并将目标导入到调用该项目的项目中include

install可以将库安装到的另一个公共子目录中projects/。根据您的源目录结构,这样做的好处是仅使预期的库API标头可用于相关项目。

但是,这两个选项都需要在修改后重建(并安装)依赖库项目,而您当前的设置包括项目中的所有依赖目标,因此对依赖库中源文件的任何更改都将导致您test目标要过时。

有关进一步的细节exportinstall运行:

cmake --help-command export
cmake --help-command install
Run Code Online (Sandbox Code Playgroud)

  • 在某些情况下,您可以将依赖项 lib1 唯一分配给 lib2,反之亦然。但也有一些常见的情况,您想要构建松散耦合的模块(考虑不同的插件),这些模块共享依赖项。例如,您有 prog1,它具有依赖项 lib1 和 lib2,而 prog2 具有依赖项 lib2 和 lib3。现在,如果您想要不同的组合(例如,在本例中您不需要 prog2,因此您只需不包含它即可),那么如果 lib2 是 prog2 的依赖项,则可能会出现问题,因为它不再可用。 (2认同)