处理具有多个子项目的 CMake 项目的依赖关系

时间:2021-03-11 21:19:19

标签: c++ cmake

我的项目结构如下:

    ├── CMakeLists.txt
    ├── libA
    │   ├── CMakeLists.txt
    │   ├── include
    │   │   └── libA
    │   │       └── my_liba.h
    │   ├── src
    │   │   └── my_liba.cpp
    │   └── test
    ├── libB
    │   ├── CMakeLists.txt
    │   ├── include
    │   │   └── libB
    │   │       └── my_libb.h
    │   ├── src
    │   │   └── my_libb.cpp
    │   └── test
    └── runner
        ├── CMakeLists.txt
        └── src
            └── main.cpp

我想实现以下目标:

  • 能够分别构建 libAlibBRunner
  • 能够一起构建。

对于依赖项:libB 依赖于 libARunner 需要 libB。 我必须如何配置 libB 和 Runner?

这些是当前的 CMakeLists.txt 文件:

libA/CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project (MyLibA)

add_library(${PROJECT_NAME} src/my_liba.cpp)
add_library(Example::LibA ALIAS ${PROJECT_NAME})

target_include_directories( ${PROJECT_NAME}
    PUBLIC ${PROJECT_SOURCE_DIR}/include
)

libB/CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project (MyLibB)

add_library(${PROJECT_NAME} src/my_libb.cpp)
add_library(Example::LibB ALIAS ${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} PRIVATE Example::LibA)

target_include_directories( ${PROJECT_NAME}
    PUBLIC ${PROJECT_SOURCE_DIR}/include
)

Runner/CMakeLists.txt

project(runner)

add_executable(${PROJECT_NAME} src/main.cpp)

target_link_libraries(${PROJECT_NAME}
    Example::LibB
)

CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)

project(Example)

add_subdirectory(libA)
add_subdirectory(libB)
add_subdirectory(runner)

使用当前配置,我可以从 lib 目录中构建所有内容。 我还可以从 libA 目录内部构建 libA。但是我无法从那里构建 libBrunner 文件夹,这是意料之中的,因为他们不知道在哪里可以找到依赖项。

我必须如何更改我的 CMakeFiles 才能使其正常工作?

2 个答案:

答案 0 :(得分:0)

如果您希望能够仅使用 libB 构建脚本构建 libB,您需要一种使 libB 能够找到 libA 依赖项的方法。

根据您的问题,我假设您实际上希望将 libA 构建为 libB 构建过程的一部分(您不想在开始 libA 之前安装 libB } 构建。

这看起来很奇怪,但您可以在 libB/CMakeLists.txt 中执行此操作:

add_subdirectory(../libA)

问题是这样做会破坏根构建脚本。这可以通过检查 libA 目标是否已经存在来解决:

if (NOT TARGET libA)
    add_subdirectory(../libA)
endif (NOT TARGET libA)

这样,您要么拥有 libA 目标,因为根构建脚本添加了 libA 子目录,或者您自己添加了它。

add_subdirectory(../libA) 对我来说看起来很奇怪,可能一些有更多 CMake 经验的人会认为它的风格很糟糕,但鉴于您的设置,我在这里看不到其他选项。如果您这样做,其他事情可能会中断,请参阅 this question

作为旁注,您可能希望在目标之间添加一些依赖项:

add_dependencies(libB libA)

这样,当您构建 libB 时,如果 libA 未构建,则会在 libA 构建开始之前触发 libB 构建。

答案 1 :(得分:0)

add_subdirectory 允许您传递任何目录。如果您不传递子目录,则需要传递第二个参数,指定用于源“子树”的二进制目录。当然,您需要确保不要创建圈子。

这允许您添加目标所依赖的项目的源目录,从而导致包含以下源目录:

  • libB/CMakeLists.txt 包括 libA
  • runner/CMakeLists.txt 包括 libB
  • CMakeLists.txt 要么包含 runner 或完全删除(您可以简单地使用 runner 作为源目录)< /li>

用于二进制目录的方便位置是二进制目录的子目录。

对您的 CMakeLists.txt 文件的更改

libA/CMakeLists.txt

保持不变

libB/CMakeLists.txt

创建一个用作源目录的目录并添加 add_subdirectory

set(LIB_A_BINARY_DIR "${CMAKE_BINARY_DIR}/subproject_build_dirs/libA")
file(MAKE_DIRECTORY ${LIB_A_BINARY_DIR})
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../libA" ${LIB_A_BINARY_DIR})

runner/CMakeLists.txt

与上述更改类似,但如果您想使用 cmake_minimum_required 作为源目录,还要添加 runner 以避免 cmake 产生警告。

cmake_minimum_required(VERSION 3.14)

set(LIB_B_BINARY_DIR "${CMAKE_BINARY_DIR}/subproject_build_dirs/libB")
file(MAKE_DIRECTORY ${LIB_B_BINARY_DIR})
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../libB" ${LIB_B_BINARY_DIR})

CMakeLists.txt

如果你想保留这个文件而不是直接使用 runner/CMakeLists.txt 应该改为以下内容

cmake_minimum_required(VERSION 3.14)

project(Example)

add_subdirectory(runner)