使用 cmake 获取外部依赖
Getting external dependency with cmake
我正在用 c++ 编写一个没有外部依赖项的小型库,除了测试我想使用 catch2 的地方。所以我宁愿不包含该项目,并认为我可以 在需要时使用 cmake 下载它,但到目前为止,看起来 cmake 只在我执行 makefile
时下载
这是有问题的,因为 CMakeList 文件的其余部分依赖于它已经被下载,因此它可以使用 catch2 提供的 cmake 函数;没有它构建失败。
我的后续方法如下所示
./CMakeList.txt:
cmake_minimum_required(VERSION 3.9)
project(projectname VERSION 0.0.1)
enable_language(CXX CUDA)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
add_definitions(-DNVRTC_GET_TYPE_NAME=1)
include_directories(include)
link_libraries(cuda nvrtc)
file(GLOB SOURCES "*.cpp")
add_subdirectory(examples)
add_subdirectory(test)
./examples/CMakeList.txt:
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-Wall -Dcurrent_log_level=loglevel::DEBUG1)
endif ()
add_executable(example_saxpy ${SOURCES} example_saxpy.cpp)
add_executable(example_program ${SOURCES} example_program.cpp)
add_executable(example_template ${SOURCES} example_template.cpp)
./test/CMakeList.txt:
file(GLOB TESTS "*.cpp")
add_executable(tests ${SOURCES} ${TESTS})
find_package(Catch2 CONFIG)
if (${Catch2_FOUND})
else ()
message(STATUS "downloading Catch2")
include(ExternalProject)
ExternalProject_Add(
catch2
PREFIX ${PROJECT_SOURCE_DIR}/lib/catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
TIMEOUT 10
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
add_dependencies(tests catch2)
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
ExternalProject_Get_Property(catch2 source_dir)
set(CATCH_INCLUDE_DIR ${source_dir}/include CACHE INTERNAL "Path to include folder for Catch2")
add_subdirectory(${PROJECT_SOURCE_DIR}/lib/catch2)
include_directories(${CATCH_INCLUDE_DIR})
endif ()
enable_testing(true)
target_link_libraries(tests Catch2::Catch2)
include(CTest)
include(Catch)
catch_discover_tests(tests)
具有以下项目结构
projectname
├── bin
├── build
├── CMakeLists.txt
├── examples
│ └── CMakeLists.txt
├── include
└── $projectname
├── src
└── test
└── CMakeLists.txt
现在这根本行不通,因为我仍然误解了哪些变量在多个 cmakefile 之间的作用域,但是将这些全部放在一个 CmakeList 中仍然不会让 add_subdirectory 发现 Catch2。
我的另一个想法是将它作为一个 git 子模块包含进来,如果这样可以允许 cmake 在执行 makefile 之前下载 catch2。
所以总的来说,我想让我的 gitrepo 尽可能小,并且只在需要时获取依赖项。
我最终选择了子模块,因为 fetchContent 运行良好,但仅在 cmake v3.11 中受支持
我遵循了这个 googletest 指南 https://cliutils.gitlab.io/modern-cmake/chapters/testing/googletest.html
./test/CMakeList catch2 子模块位于 extern/catch2:
file(GLOB TESTS "*.cpp")
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp")
add_executable(tests ${SOURCES} ${TESTS})
SET(catch2_dir ${PROJECT_SOURCE_DIR}/extern/catch2)
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# Update submodules as needed
option(GIT_SUBMODULE "Check submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Submodule update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
endif()
if(NOT EXISTS "${catch2_dir}/CMakeLists.txt")
message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.")
endif()
add_subdirectory(${catch2_dir} ${CMAKE_CURRENT_SOURCE_DIR}/catch_build)
list(APPEND CMAKE_MODULE_PATH "${catch2_dir}/contrib/")
target_link_libraries(tests Catch2::Catch2)
include(CTest)
include(Catch)
catch_discover_tests(tests)
我正在用 c++ 编写一个没有外部依赖项的小型库,除了测试我想使用 catch2 的地方。所以我宁愿不包含该项目,并认为我可以 在需要时使用 cmake 下载它,但到目前为止,看起来 cmake 只在我执行 makefile
时下载这是有问题的,因为 CMakeList 文件的其余部分依赖于它已经被下载,因此它可以使用 catch2 提供的 cmake 函数;没有它构建失败。
我的后续方法如下所示
./CMakeList.txt:
cmake_minimum_required(VERSION 3.9)
project(projectname VERSION 0.0.1)
enable_language(CXX CUDA)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
add_definitions(-DNVRTC_GET_TYPE_NAME=1)
include_directories(include)
link_libraries(cuda nvrtc)
file(GLOB SOURCES "*.cpp")
add_subdirectory(examples)
add_subdirectory(test)
./examples/CMakeList.txt:
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-Wall -Dcurrent_log_level=loglevel::DEBUG1)
endif ()
add_executable(example_saxpy ${SOURCES} example_saxpy.cpp)
add_executable(example_program ${SOURCES} example_program.cpp)
add_executable(example_template ${SOURCES} example_template.cpp)
./test/CMakeList.txt:
file(GLOB TESTS "*.cpp")
add_executable(tests ${SOURCES} ${TESTS})
find_package(Catch2 CONFIG)
if (${Catch2_FOUND})
else ()
message(STATUS "downloading Catch2")
include(ExternalProject)
ExternalProject_Add(
catch2
PREFIX ${PROJECT_SOURCE_DIR}/lib/catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
TIMEOUT 10
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
add_dependencies(tests catch2)
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
ExternalProject_Get_Property(catch2 source_dir)
set(CATCH_INCLUDE_DIR ${source_dir}/include CACHE INTERNAL "Path to include folder for Catch2")
add_subdirectory(${PROJECT_SOURCE_DIR}/lib/catch2)
include_directories(${CATCH_INCLUDE_DIR})
endif ()
enable_testing(true)
target_link_libraries(tests Catch2::Catch2)
include(CTest)
include(Catch)
catch_discover_tests(tests)
具有以下项目结构
projectname
├── bin
├── build
├── CMakeLists.txt
├── examples
│ └── CMakeLists.txt
├── include
└── $projectname
├── src
└── test
└── CMakeLists.txt
现在这根本行不通,因为我仍然误解了哪些变量在多个 cmakefile 之间的作用域,但是将这些全部放在一个 CmakeList 中仍然不会让 add_subdirectory 发现 Catch2。
我的另一个想法是将它作为一个 git 子模块包含进来,如果这样可以允许 cmake 在执行 makefile 之前下载 catch2。
所以总的来说,我想让我的 gitrepo 尽可能小,并且只在需要时获取依赖项。
我最终选择了子模块,因为 fetchContent 运行良好,但仅在 cmake v3.11 中受支持
我遵循了这个 googletest 指南 https://cliutils.gitlab.io/modern-cmake/chapters/testing/googletest.html
./test/CMakeList catch2 子模块位于 extern/catch2:
file(GLOB TESTS "*.cpp")
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp")
add_executable(tests ${SOURCES} ${TESTS})
SET(catch2_dir ${PROJECT_SOURCE_DIR}/extern/catch2)
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# Update submodules as needed
option(GIT_SUBMODULE "Check submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Submodule update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
endif()
if(NOT EXISTS "${catch2_dir}/CMakeLists.txt")
message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.")
endif()
add_subdirectory(${catch2_dir} ${CMAKE_CURRENT_SOURCE_DIR}/catch_build)
list(APPEND CMAKE_MODULE_PATH "${catch2_dir}/contrib/")
target_link_libraries(tests Catch2::Catch2)
include(CTest)
include(Catch)
catch_discover_tests(tests)