如何防止 cmake 不使用现代 cmake 结构添加来自外部依赖项的所有目标

rat*_*h3t 5 c++ cmake eigen

我正在尝试以最干净、最现代的 cmake 方式将外部依赖项添加到我的新 cmake 项目中。\n我想在配置期间下载这些依赖项。我的问题是来自外部依赖项的所有目标始终都是导入的。这会垃圾邮件我在例如 Clion 中的配置,我希望默认情况下更干净,但正如你所看到的,我有几个来自 gtest、googlebenchmark、eigen 和 spdlog 的无用目标,如下图所示。该项目应在 Windows 和 Linux 上编译。

\n

在此输入图像描述

\n

所以我的问题是如何防止这种情况发生?

\n

我观看了几个现代 cmake 视频,例如\n https://www.youtube.com/watch?v=eC9-iRN2b04以及https://cliutils.gitlab.io/modern-cmake/的来源。

\n

我的项目文件夹结构如下

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 Ikarus\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 addexternalLibs.cmake\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Ikarus\n\xe2\x94\x82           \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 [...]\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 problems\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 [.cpp files]\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 tests\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 [.cpp files]\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 benchmarks\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n|   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 [.cpp files]\n
Run Code Online (Sandbox Code Playgroud)\n

我有一个顶级CMakeLists.txt如下

\n
cmake_minimum_required(VERSION 3.16)\nproject(Ikarus)\n\nadd_subdirectory(Ikarus)\nadd_subdirectory(problems)\nadd_subdirectory(tests)\nadd_subdirectory(benchmarks)\n
Run Code Online (Sandbox Code Playgroud)\n

Ikarus在我想要构建的文件夹中,它应该由、和Ikarus_lib中定义的目标使用。problemstestsbenchmarks

\n

该文件Ikarus/CMakeLists.txt如下所示

\n
file(GLOB_RECURSE IKARUS_CPP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS  *.cpp )\n\n\nadd_library(${PROJECT_NAME}_lib STATIC)\ntarget_sources(${PROJECT_NAME}_lib PRIVATE ${IKARUS_CPP_SOURCES})\n\ninclude(addexternalLibs.cmake)\n\ntarget_include_directories(${PROJECT_NAME}_lib PUBLIC src)\n\ntarget_link_libraries(${PROJECT_NAME}_lib PUBLIC Eigen3::Eigen\n                                          PUBLIC spdlog::spdlog)\n
Run Code Online (Sandbox Code Playgroud)\n

现在我想谈谈Ikarus/addexternalLibs.cmake导入外部依赖项的文件的内容。在我导入 googletest 和 googlebenchmark 的基准测试和测试中也会出现类似的困难,但我认为我会将自己限制在 Ikarus_lib 情况下,因为困难是相同的。

\n

由于我想在配置期间下载我的依赖项,我使用https://cmake.org/cmake/help/latest/module/FetchContent.html找到了很好的解决方案

\n

结果是Ikarus/addexternalLibs.cmake:

\n
include(FetchContent)\n\nmessage("Configure Eigen: ")\n\nFetchContent_Declare(\n        eigen\n        GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git\n        GIT_TAG 3.4\n        GIT_SHALLOW TRUE\n        GIT_PROGRESS TRUE\n)\noption(EIGEN_BUILD_DOC OFF)\noption(BUILD_TESTING OFF)\noption(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF)\noption(EIGEN_BUILD_PKGCONFIG OFF)\nFetchContent_MakeAvailable(eigen)\n\nmessage("====================================")\nmessage("Configure spdlog: ")\n\nFetchContent_Declare(\n        spdlog\n        GIT_REPOSITORY https://github.com/gabime/spdlog.git\n        GIT_TAG v1.8.5\n        GIT_SHALLOW TRUE\n        GIT_PROGRESS TRUE\n)\noption(SPDLOG_BUILD_SHARED OFF)\noption(SPDLOG_BUILD_ALL OFF)\nFetchContent_MakeAvailable(spdlog)\n
Run Code Online (Sandbox Code Playgroud)\n

这个解决方案有效,我设法使用选项停用一些目标EIGEN_BUILD_DOC OFF...。但我仍然有很多不同的无用目标,如上图所示,无法使用包的选项来停用它们。

\n

我尝试了其他一些方法,例如使用EXCLUDE_FROM_ALL https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html如下

\n
FetchContent_Declare(\n        eigen\n        GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git\n        GIT_TAG 3.4\n        GIT_SHALLOW TRUE\n        GIT_PROGRESS TRUE\n)\noption(EIGEN_BUILD_DOC OFF)\noption(BUILD_TESTING OFF)\noption(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF)\noption(EIGEN_BUILD_PKGCONFIG OFF)\n\nFetchContent_GetProperties(eigen)\nif(NOT eigen_POPULATED)\n   FetchContent_Populate(Eigen)\n    add_subdirectory(${eigen_SOURCE_DIR} ${eigen_BINARY_DIR} EXCLUDE_FROM_ALL)\nendif()\n
Run Code Online (Sandbox Code Playgroud)\n

这也有效,但也添加了我不想要的所有目标。因此,EXCLUDE_FROM_ALL它并不像我认为的那样工作。

\n

另一种使用方法EXCLUDE_FROM_ALL可能是

\n
include(FetchContent)\n\nmessage("Configure Eigen: ")\n\nFetchContent_Declare(\n        eigen\n        GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git\n        GIT_TAG 3.4\n        GIT_SHALLOW TRUE\n        GIT_PROGRESS TRUE\n)\noption(EIGEN_BUILD_DOC OFF)\noption(BUILD_TESTING OFF)\noption(EIGEN_LEAVE_TEST_IN_ALL_TARGET OFF)\noption(EIGEN_BUILD_PKGCONFIG OFF)\nFetchContent_MakeAvailable(eigen)\nset_target_properties(eigen PROPERTIES EXCLUDE_FROM_ALL TRUE)\n
Run Code Online (Sandbox Code Playgroud)\n

这也不会改变行为。

\n

我也尝试CPMAddPackage过https://github.com/cpm-cmake/CPM.cmake

\n
CPMAddPackage(\n        GITLAB_REPOSITORY libeigen/eigen\n        GIT_TAG 3.4\n        OPTIONS "EIGEN_BUILD_DOC NO"\n                "BUILD_TESTING NO"\n                "EIGEN_LEAVE_TEST_IN_ALL_TARGET YES"\n                "EIGEN_BUILD_PKGCONFIG NO"\n)\n
Run Code Online (Sandbox Code Playgroud)\n

这也有效,但也添加了所有目标。

\n

所以现在我不知道还能尝试什么,我想我只会保留目标并将它们从我的 Clion 配置界面中删除,并希望它们不会再次出现。但我仍然想了解我错过了什么。我认为这是一个常见问题,解决方案应该很容易?

\n

此外,我知道我可以下载例如 eigen 并用于include_directories(...)自动添加没有目标的标头。但一方面,这不是https://www.youtube.com/watch?v=eC9-iRN2b04中宣传的现代 cmake ,其中使用include_directories被称为反模式,人们应该“以模块的方式思考”。另一方面,这对于非标头的包没有帮助。

\n

那么如何优雅地解决这个问题呢?另外,我很感激对我对 Cmake 的(糟糕)使用的所有其他评论。谢谢!

\n