【问题标题】:Handling of Dependecies on a CMake Project with multiple subprojects处理具有多个子项目的 CMake 项目的依赖关系
【发布时间】:2021-03-11 21:19:19
【问题描述】:

我的项目结构如下:

    ├── 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 依赖于libA,而Runner 需要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 才能使其正常工作?

【问题讨论】:

  • 为什么要从子目录运行make?只需从构建目录的根目录运行make <appropriate_target>
  • 我希望能够将libAlibB 也构建为独立库。
  • 当您从其文件夹构建 libB 时,您希望它如何找到 libA? libA 是否已经安装在系统上,还是您希望 libB 也构建 libA?
  • @yemre 那就是我不知道什么是最好的解决方案,或者cmake是否有最佳实践

标签: c++ cmake


【解决方案1】:

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

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

这看起来很奇怪,但您可以在 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,在libB构建开始之前会触发一个libA构建。

【讨论】:

  • 用libA的目录定义变量是否也是一种替代方法?这样就可以在构建过程中设置变量?
  • 是的。例如传递-DPATH_TO_LIBA=some/path.here 会将变量PATH_TO_LIBA 设置为some/path/here。您可以检查它是否设置为if:if (PATH_TO_LIBA)
  • 然后它就像@fabian 我猜的答案一样工作
  • 是的。我的回答假设您需要按原样的根构建脚本,但他简化了事情。
【解决方案2】:

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

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

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

二进制目录的一个方便的位置是二进制目录的子目录。

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

与上述更改类似,但如果您想使用runner 作为源目录,还要添加cmake_minimum_required 以避免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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 2012-12-04
    • 1970-01-01
    相关资源
    最近更新 更多