具有冗余依赖项的子模块的 CMake 项目

CMake projects with submodules that have redudant dependencies

我有以下项目结构:

root-project/
|-> CMakeLists.txt
|-> src/
    |-> foo.cpp
|-> include/
    |-> foo.hpp
|-> test/
    |-> test_foo.cpp
    |-> googletest/
        |-> CMakeLists.txt
        |-> ...
|-> libs/
    |-> my-lib/
        |-> CMakeLists.txt
        |-> src/
            |-> bar.cpp
        |-> include/
            |-> bar.hpp
        |-> test/
            |-> test_bar.cpp
            |-> googletest/
                |-> CMakeLists.txt
                |-> ...

root-project 构建了一个名为 foo 的可执行文件,它依赖于库 my-libroot-projectmy-lib 都使用 googletest 进行测试,它包含在 git-submodule.

我已经接受了使用 git-submodule 会有多余的 googletest 目录的事实。然而,问题是简单地使用 add_subdirectory 连接整个项目将最终得到多个 gtest 目标。

我的问题:有没有办法让 root-project 构建 my-lib 并且只看到目标 my-lib 而不是测试目标googletest? (即,在构建期间冗余 googletest 可以是 "hidden" 吗?)

我的第二个问题:鉴于我的 CMake 菜鸟身份,我是否以有缺陷的方式组织了这些项目?是否有更受欢迎的方式来组织避免此问题的项目?欢迎提出建设性的 CMake 建议!

我不确定这是否是这种情况下的最佳做法,但我最终在我的项目中所做的是编写一个 cmake 模块 gtest.cmake 以将 gtest 添加到我的项目中。在该模块中,我检查它是否已经添加,如果是,我只是重新使用生成的 ${gtest_SOURCE_DIR} 变量:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.3)
project(myProject CXX)

set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake")

include(gtest)

# myTarget definition

include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
target_link_libraries(myTarget gtest gtest_main)

cmake/gtest.cmake:

if(gtest_SOURCE_DIR)
    message(STATUS "gtest variables already defined. Skipping.")
else()
    add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/external/gtest")
endif()

编辑:
我对测试目标所做的通常是使用 add_executableEXCLUDE_FROM_ALL 属性 从常规构建中排除它们。您还可以将该标志用于 add_subdirectory,这样只有当您想要 运行 测试时,您才可以包含 gtest。例如,您可以在 CMakeLists.txt:

中写这样的内容
# set ${TESTS_SOURCE_FILES} with the source files of your tests

include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
add_executable(${PROJECT_NAME}_tests EXCLUDE_FROM_ALL ${TESTS_SOURCE_FILES})

target_link_libraries(${PROJECT_NAME}_tests gtest gtest_main)

并让你的 cmake/gtest.cmake 写成这样:

if(gtest_SOURCE_DIR)
    message(STATUS "gtest variables already defined. Skipping.")
else()
    add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/external/gtest" EXCLUDE_FROM_ALL)
endif()

然后,只有当您 make 明确测试目标时,通过 运行ning make myProject_tests 它将只构建它需要的测试目标。

希望对您有所帮助!