对于C++和CMake,目前还没有被普遍接受的管理、打包依赖库的方法。然而,近几年出现了一些新的有趣的包管理系统。
虽然这些系统,对于CMake而言,是一个独立的系统,但它们大多数都被集成到了CMake的构建系统中。

相关链接

  1. https://github.com/ttroy50/cmake-examples.git中的示例7(07-package-management)
  2. find_package

使用系统提供的包(find_package)

使用系统提供的包是最古老、最常见的包管理解决方案之一。

使用步骤:

  1. 您可以使用系统包安装程序(例如apt、yum)将库和头文件安装到最常见的位置
  2. 然后可以使用find_package函数来搜索这些内容

附:CMake官方为我们预定义了许多寻找依赖包的Module

将第三方库放在工程中(Vendoring code)

Vendoring code意味着将第三方库存储在仓库中,并将其作为项目的一部分进行构建。

添加CMake已经安装好的包(find_package)

经过CMake安装过的包,它们会自带Find<LibraryName>.cmake文件,这些文件能够让CMake找到对应的包
而我们要做的就是

  1. 手动指定Find<LibraryName>.cmake所在目录
  2. 使用find_package即可

附:在CMake脚本中指定模块目录(即CMAKE_MODULE_PATH目录)

  • CMake会去CMAKE_MODULE_PATH下搜索Find<LibraryName>.cmake文件 ```

    将${CMAKE_SOURCE_DIR}/cmake/modules路径添加到CMAKE_MODULE_PATH中

    set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules
    1. ${CMAKE_MODULE_PATH})

方法二

list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)

  1. <a name="nqLHp"></a>
  2. #### 例子:指定VTK的路径

指定VTK的路径

set(VTK_DIR D:\3rdparty\vtk-9.0.1\lib\cmake\vtk-9.0) SET(CMAKE_INCLUDE_CURRENT_DIR ON) #启用当前目录

  1. <a name="TRRxK"></a>
  2. #### 例子:指定Qt的路径

指定Qt的路径

set(Qt5_DIR C:\Qt\Qt5.15.2msvc2017_64) SET(CMAKE_PREFIX_PATH ${Qt5_DIR}) #Qt路径

list(APPEND CMAKE_PREFIX_PATH ${Qt5_DIR}) #如果CMAKE_PREFIX_PATH有多个,可以使用这个添加

SET(CMAKE_INCLUDE_CURRENT_DIR ON) #启用当前目录

  1. <a name="S2Oj5"></a>
  2. ### 第三方库不支持CMake,自己编写CMake文件
  3. 有一些第三方库本身不支持CMake,或者是你编译时,忘记install了<br />此时,我们可以手动编写CMake文件,让我们的CMake能够发现它
  4. <a name="a3cFK"></a>
  5. #### 例:编写CMakeLists.txt(catch2)
  6. > 例子链接:[https://github.com/ttroy50/cmake-examples.git](https://github.com/ttroy50/cmake-examples.git)中,05-unit-testing\catch2-vendored
  7. 将catch2放到仓库中

. ├── 3rd_party │ └── catch2 │ ├── catch2 │ │ └── catch.hpp │ └── CMakeLists.txt ├── CMakeLists.txt └── src ├── … └── example.cpp

  1. 实际上catch2的源代码只有一个头文件catch2.hpp,这种情况下,我们可以自己编写CMakeLists.txt

.\3rd_party\catch2\CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(catch2)

Prepare “Catch2” library for other executables

add_library(Catch2 INTERFACE) add_library(Catch2::Test ALIAS Catch2) target_include_directories(Catch2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

  1. 然后在顶部的CMake文件中加入此模块

.\CMakeLists.txt

cmake_minimum_required(VERSION 3.5) project (catch2_unit_test)

set(CMAKE_CXX_STANDARD 11)

add the CMakeFile that defines catch2

add_subdirectory(3rd_party/catch2)

Add an library for the example classes

add_library(example_unit_test example.cpp )

#

Unit tests

enable CTest testing

enable_testing()

Add a testing executable

add_executable(unit_tests unit_tests.cpp)

target_link_libraries(unit_tests example_unit_test Catch2::Test )

add_test(test_all unit_tests)

  1. <a name="QoVsh"></a>
  2. #### 例:自己编写Find<PackageName>.cmake
  3. 假设我们编写了一个新的函数库,我们希望别的项目可以通过find_package对它进行引用我们应该怎么办呢。
  4. 1. FindAdd.cmake
  5. ```powershell
  6. # 定义Add模块的Include_Dir
  7. find_path(ADD_INCLUDE_DIR
  8. libadd.h #文件名
  9. #多个搜索路径
  10. /usr/include/
  11. /usr/local/include
  12. ${CMAKE_SOURCE_DIR}/ModuleMode
  13. )
  14. #搜索包含某个文件的路径
  15. # 定义Add模块的Lib目录
  16. find_library(ADD_LIBRARY #Add库的Lib目录
  17. NAMES #lib文件名称
  18. add
  19. PATHS #搜索路径
  20. /usr/lib/add
  21. /usr/local/lib/add
  22. ${CMAKE_SOURCE_DIR}/ModuleMode
  23. )
  1. 使用 ```powershell

    将项目目录下的cmake文件夹加入到CMAKE_MODULE_PATH中,让find_pakcage能够找到我们自定义的函数库

    set(CMAKE_MODULE_PATH “${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}”)

add_executable(addtest addtest.cc)

find_package(ADD) if(ADD_FOUND) target_include_directories(addtest PRIVATE ${ADD_INCLUDE_DIR}) target_link_libraries(addtest ${ADD_LIBRARY}) else(ADD_FOUND) message(FATAL_ERROR “ADD library not found”) endif(ADD_FOUND)

  1. <a name="GreEN"></a>
  2. ## 外部工程
  3. CMake支持使用[External Project](https://cmake.org/cmake/help/latest/module/ExternalProject.html)命令下载和构建一个外部项目
  4. - 通过ExternalProject_Add命令,让CMake自动从HTTP或源代码控制系统(如Git)中下载一个源文件
  5. - 一旦配置好,外部项目将生成一个自定义目标,该目标可用于控制外部项目的下载、更新、构建、测试和安装阶段
  6. <a name="JaNLd"></a>
  7. ##### 例:使用Google Test
  8. > 例子完整链接:[https://github.com/ttroy50/cmake-examples.git](https://github.com/ttroy50/cmake-examples.git)中,05-unit-testing\google-test-download

. ├── 3rd_party │ └── google-test │ ├── CMakeLists.txt │ └── CMakeLists.txt.in ├── CMakeLists.txt ├── Reverse.h ├── Reverse.cpp ├── Palindrome.h ├── Palindrome.cpp ├── unit_tests.cpp

.\3rd_party\google-test\CMakeLists.txt.in

cmake_minimum_required(VERSION 3.0)

project(googletest-download NONE)

include(ExternalProject)

Version bfc0ffc8a698072c794ae7299db9cb6866f4c0bc happens to be master when I set this up.

To prevent an issue with accidentally installing GTest / GMock with your project you should use a

commit after 9469fb687d040b60c8749b7617fee4e77c7f6409

Note: This is after the release of v1.8

ExternalProject_Add(googletest URL https://github.com/google/googletest/archive/bfc0ffc8a698072c794ae7299db9cb6866f4c0bc.tar.gz SOURCE_DIR “${CMAKE_CURRENT_BINARY_DIR}/googletest-src” BINARY_DIR “${CMAKE_CURRENT_BINARY_DIR}/googletest-build” CONFIGURE_COMMAND “” BUILD_COMMAND “” INSTALL_COMMAND “” TEST_COMMAND “” )

# .\3rd_party\google-test\CMakeLists.txt

Download and unpack googletest at configure time

See: http://crascit.com/2015/07/25/cmake-gtest/

configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)

Call CMake to download and Google Test

execute_process(COMMAND ${CMAKE_COMMAND} -G “${CMAKE_GENERATOR}” . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) if(result) message(FATAL_ERROR “CMake step for googletest failed: ${result}”) endif()

Build the downloaded google test

execute_process(COMMAND ${CMAKE_COMMAND} —build . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) if(result) message(FATAL_ERROR “Build step for googletest failed: ${result}”) endif()

Prevent overriding the parent project’s compiler/linker

settings on Windows

set(gtest_force_shared_crt ON CACHE BOOL “” FORCE)

Prevent installation of GTest with your project

set(INSTALL_GTEST OFF CACHE BOOL “” FORCE) set(INSTALL_GMOCK OFF CACHE BOOL “” FORCE)

Add googletest directly to our build. This defines

the gtest and gtest_main targets.

add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src ${CMAKE_CURRENT_BINARY_DIR}/googletest-build)

This is a bit of a hack that can be used to get gtest libraries to build in C++11 if you aren’t using CMAKE_CXX_STANDARD

#

set(CXX11_FEATURES

cxx_nullptr

cxx_auto_type

cxx_delegating_constructors

)

target_compile_features(gtest

PRIVATE

${CXX11_FEATURES}

)

#

target_compile_features(gmock_main

PRIVATE

${CXX11_FEATURES}

)

#

target_compile_features(gmock

PRIVATE

${CXX11_FEATURES}

)

#

target_compile_features(gmock_main

PRIVATE

${CXX11_FEATURES}

)

Add aliases for GTest and GMock libraries

if(NOT TARGET GTest::GTest) add_library(GTest::GTest ALIAS gtest) add_library(GTest::Main ALIAS gtest_main) endif()

if(NOT TARGET GTest::GMock) add_library(GMock::GMock ALIAS gmock) add_library(GMock::Main ALIAS gmock_main) endif() ```

Conan

Conan是一个开源、去中心化、多平台的包管理器