5 cmake官方示例 CMake教程通过一个示例项目, 逐步介绍了CMake构建系统的主要功能, 包括:
生成执行程序
生成库(使用旧式CMake宏定义方法)
生成库(使用新式CMake宏定义方法—使用要求)
基于源代码的安装与测试
系统检测
添加自定义命令以及生成文件
构建安装程序
将测试结果提交到Kitware的公共指示板
混合静态和共享(动态)库
生成器表达式,条件判断
find_package() 支持(添加导出配置)
将调试版和发行版打包在一起(win10试验没有成功)
注:
示例项目目录在CMake源代码树的Help\guide\tutorial
目录
本摘要主要关注CMake使用, 一些关于源代码的更改在请查看CMake教程
CMake教程示例代码,下一步的内容都是上一步的结果
主要功能摘要 5.1. 生成执行程序 本节示例展示了:
生成执行程序的基本构建系统框架;
将一些CMake属性通过配置文件输出;
如何在目标中添加头文件搜索路径;
常规CMake命令行使用方式
注: 本节示例初始代码在示例目录的Step1
子目录, 成果在Step2
子目录
核心代码 顶层目录的CMakeLists.txt 内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 cmake_minimum_required (VERSION 3.10 )project (Tutorial VERSION 1.0 )set (CMAKE_CXX_STANDARD 11 )set (CMAKE_CXX_STANDARD_REQUIRED True )configure_file (TutorialConfig.h.in TutorialConfig.h)add_executable (Tutorial tutorial.cxx)target_include_directories (Tutorial PUBLIC "${PROJECT_BINARY_DIR}" )
TutorialConfig.h.in 内容如下:
1 2 3 #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
命令行使用示例 在项目目录下
1 2 3 4 $ mkdir build $ cd build $ cmake .. $ cmake --build .
5.2. 生成库(旧式CMake) 在上一步的基础上, 本节示例展示了:
生成库;
在项目中添加库;
使用可选项,并将可选项保存到配置文件中;
目标链接库的旧式方法;
目标包含库头文件目录的旧式方法;
注: 本节示例初始代码在示例目录的Step2
子目录, 成果在Step3
子目录
生成库
创建库目录;
在库目录CMakeLists.txt 中, 添加生成库命令如下:
1 2 add_library (MathFunctions mysqrt.cxx)
其它核心代码 项目CMakeLists.txt 内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 cmake_minimum_required (VERSION 3.10 )project (Tutorial VERSION 1.0 )set (CMAKE_CXX_STANDARD 11 )set (CMAKE_CXX_STANDARD_REQUIRED True )option (USE_MYMATH "Use tutorial provided math implementation" ON )configure_file (TutorialConfig.h.in TutorialConfig.h)if (USE_MYMATH) add_subdirectory (MathFunctions) list (APPEND EXTRA_LIBS MathFunctions) list (APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions" ) endif ()add_executable (Tutorial tutorial.cxx)target_link_libraries (Tutorial PUBLIC ${EXTRA_LIBS} )target_include_directories (Tutorial PUBLIC "${PROJECT_BINARY_DIR}" ${EXTRA_INCLUDES} )
TutorialConfig.h.in 内容如下:
1 2 3 4 #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ #cmakedefine USE_MYMATH
5.3. 生成库(新式CMake) 在上一步的基础上, 本节示例展示了:
在库中使用INTERFACE ;
在项目中添加库;
使用可选项,并将可选项保存到配置文件中;
目标链接库的旧式方法;
目标包含库头文件目录的旧式方法;
注: 本节示例初始代码在示例目录的Step3
子目录, 成果在Step4
子目录
核心代码更改 库目录CMakeLists.txt 内容如下:
1 2 3 4 5 6 7 8 add_library (MathFunctions mysqrt.cxx)target_include_directories (MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} )
项目CMakeLists.txt 删除了EXTRA_INCLUDES 相关代码, 变化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 cmake_minimum_required (VERSION 3.10 )project (Tutorial VERSION 1.0 )set (CMAKE_CXX_STANDARD 11 )set (CMAKE_CXX_STANDARD_REQUIRED True )option (USE_MYMATH "Use tutorial provided math implementation" ON )configure_file (TutorialConfig.h.in TutorialConfig.h)if (USE_MYMATH) add_subdirectory (MathFunctions) list (APPEND EXTRA_LIBS MathFunctions) endif ()add_executable (Tutorial tutorial.cxx)target_link_libraries (Tutorial PUBLIC ${EXTRA_LIBS} )target_include_directories (Tutorial PUBLIC "${PROJECT_BINARY_DIR}" )
5.4. 基于源代码的安装与测试 在上一步的基础上, 本节示例展示了:
使用基于源代码的安装规则(install);
使用测试;
注: 本节示例初始代码在示例目录的Step4
子目录, 成果在Step5
子目录
核心代码更改 库目录CMakeLists.txt 变化如下:
1 2 3 4 5 6 7 8 9 10 11 12 add_library (MathFunctions mysqrt.cxx)target_include_directories (MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) install (TARGETS MathFunctions DESTINATION lib)install (FILES MathFunctions.h DESTINATION include )
项目CMakeLists.txt 新增了安装与测试相关代码, 变化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 cmake_minimum_required (VERSION 3.10 )project (Tutorial VERSION 1.0 )set (CMAKE_CXX_STANDARD 11 )set (CMAKE_CXX_STANDARD_REQUIRED True )option (USE_MYMATH "Use tutorial provided math implementation" ON )configure_file (TutorialConfig.h.in TutorialConfig.h)if (USE_MYMATH) add_subdirectory (MathFunctions) list (APPEND EXTRA_LIBS MathFunctions) endif ()add_executable (Tutorial tutorial.cxx)target_link_libraries (Tutorial PUBLIC ${EXTRA_LIBS} )target_include_directories (Tutorial PUBLIC "${PROJECT_BINARY_DIR}" ) install (TARGETS Tutorial DESTINATION bin)install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" DESTINATION include ) enable_testing ()add_test (NAME Runs COMMAND Tutorial 25 )add_test (NAME Usage COMMAND Tutorial)set_tests_properties (Usage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number" ) function (do_test target arg result) add_test (NAME Comp${arg} COMMAND ${target} ${arg} ) set_tests_properties (Comp${arg} PROPERTIES PASS_REGULAR_EXPRESSION ${result} ) endfunction (do_test)do_test(Tutorial 4 "4 is 2" ) do_test(Tutorial 9 "9 is 3" ) do_test(Tutorial 5 "5 is 2.236" ) do_test(Tutorial 7 "7 is 2.645" ) do_test(Tutorial 25 "25 is 5" ) do_test(Tutorial -25 "-25 is [-nan|nan|0]" ) do_test(Tutorial 0.0001 "0.0001 is 0.01" )
命令行使用示例 将调试版安装 到D:\Temp2\ttt\debug
1 2 3 4 5 6 7 8 9 $ mkdir build $ cd build $ cmake .. 生成并安装调试版 $ cmake --build . $ cmake --install . --prefix D:\Temp2\ttt\debug --config Debug 生成并安装发行版 $ cmake --build . -- config Release $ cmake --install . --prefix D:\Temp2\ttt\Release --config Release
win10 VS2019 测试
在build 目录测试应用程序
1 2 3 4 5 6 7 8 9 $ mkdir build $ cd build $ cmake .. 生成并测试调试版 $ cmake --build . $ ctest -C Debug [-vv] 生成并测试发行版 $ cmake --build . -- config Release $ ctest -C Release [-vv]
5.5. 系统检测 在上一步的基础上, 本节示例展示了:
CMake系统功能检测, 以判断平台是否支持特定功能;
目标编译定义(宏定义);
注1: 本节示例初始代码在示例目录的Step5
子目录, 成果在Step6
子目录 注2: 在win10下测试失败, 没有发现log,exp函数
核心代码更改 库目录CMakeLists.txt 变化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 add_library (MathFunctions mysqrt.cxx)target_include_directories (MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) include (CheckSymbolExists)set (CMAKE_REQUIRED_LIBRARIES "m" )check_symbol_exists(log "math.h" HAVE_LOG) check_symbol_exists(exp "math.h" HAVE_EXP) if (HAVE_LOG AND HAVE_EXP) target_compile_definitions (MathFunctions PRIVATE "HAVE_LOG" "HAVE_EXP" ) endif ()install (TARGETS MathFunctions DESTINATION lib)install (FILES MathFunctions.h DESTINATION include )
5.6. 添加自定义命令以及生成文件 在上一步的基础上, 本节示例展示了:
注: 本节示例初始代码在示例目录的Step6
子目录, 成果在Step7
子目录
核心代码更改 库目录CMakeLists.txt 变化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 add_executable (MakeTable MakeTable.cxx)add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR} /Table.h COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR} /Table.h DEPENDS MakeTable ) add_library (MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR} /Table.h ) target_include_directories (MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) install (TARGETS MathFunctions DESTINATION lib)install (FILES MathFunctions.h DESTINATION include )
5.7. 构建安装程序 在上一步的基础上, 本节示例展示了:
注1: 本节示例初始代码在示例目录的Step7
子目录, 成果在Step8
子目录 注2: 为测试需要, 在win10上, 首先安装NSIS(Nulsoft Install System).
核心代码更改 顶层目录CMakeLists.txt 末尾添加如下内容即可:
1 2 3 4 5 6 include (InstallRequiredSystemLibraries)set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt" )set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}" )set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}" )include (CPack)
命令行使用示例 在项目目录下
1 2 3 4 5 6 7 8 9 $ mkdir build $ cd build $ cmake .. $ cmake --build . VS generator 注意:目录不能含有中文 生成发行版安装包(Tutorial-1.0-win64.exe) $ cmake --build . --target PACKAGE --config Release 生成调试版安装包(Tutorial-1.0-win64.exe) $ cmake --build . --target PACKAGE --config Debug
5.8. 将测试结果提交到Kitware的公共指示板 在上一步的基础上, 本节示例展示了:
注: 本节示例初始代码在示例目录的Step8
子目录, 成果在Step9
子目录
核心代码更改 顶层目录CMakeLists.txt 将:
替换为:
在顶层目录创建CTestConfig.cmake :
1 2 3 4 5 6 7 set (CTEST_PROJECT_NAME "CMakeTutorial" )set (CTEST_NIGHTLY_START_TIME "00:00:00 EST" )set (CTEST_DROP_METHOD "http" )set (CTEST_DROP_SITE "my.cdash.org" )set (CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial" )set (CTEST_DROP_SITE_CDASH TRUE )
命令行使用示例 在项目目录下
1 2 3 4 5 6 7 8 $ mkdir build $ cd build $ cmake .. VS generator 注意:目录不能含有中文 发布发行版测试结果 $ ctest [-VV] -C Release -D Experimental 发布调试版测试结果 $ ctest [-VV] -C Debug -D Experimental
5.9. 混合静态和共享库 在上一步的基础上, 本节示例展示了:
在动态库中使用静态库
使用BUILD_SHARED_LIBS
属性设置库默认生成类型(共享/非共享)(默认生成静态库);
使用目标宏定义(target_compile_definitions)设置windows动态库标志(__declspec(dllexport),__declspec(dllimport)
)
在add_library中控制库生成类型[STATIC | SHARED | MODULE]
注: 本节示例初始代码在示例目录的Step9
子目录, 成果在Step10
子目录
核心代码更改 顶层CMakeLists.txt 的起始部分更改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 cmake_minimum_required (VERSION 3.10 )project (Tutorial VERSION 1.0 )set (CMAKE_CXX_STANDARD 11 )set (CMAKE_CXX_STANDARD_REQUIRED True )set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}" )set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}" )set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}" )option (BUILD_SHARED_LIBS "Build using shared libraries" ON )configure_file (TutorialConfig.h.in TutorialConfig.h)add_subdirectory (MathFunctions)add_executable (Tutorial tutorial.cxx)target_link_libraries (Tutorial PUBLIC MathFunctions)
MathFunctions/CMakeLists.txt 更改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 add_library (MathFunctions MathFunctions.cxx)target_include_directories (MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) option (USE_MYMATH "Use tutorial provided math implementation" ON )if (USE_MYMATH) target_compile_definitions (MathFunctions PRIVATE "USE_MYMATH" ) add_executable (MakeTable MakeTable.cxx) add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR} /Table.h COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR} /Table.h DEPENDS MakeTable ) add_library (SqrtLibrary STATIC mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR} /Table.h ) target_include_directories (SqrtLibrary PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) set_target_properties (SqrtLibrary PROPERTIES POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} ) target_link_libraries (MathFunctions PRIVATE SqrtLibrary) endif ()target_compile_definitions (MathFunctions PRIVATE "EXPORTING_MYMATH" )install (TARGETS MathFunctions DESTINATION lib)install (FILES MathFunctions.h DESTINATION include )
MathFunctions/MathFunctions.h 使用dll导出(dll export)定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 #if defined(_WIN32) # if defined(EXPORTING_MYMATH) # define DECLSPEC __declspec(dllexport) # else # define DECLSPEC __declspec(dllimport) # endif #else # define DECLSPEC #endif namespace mathfunctions {double DECLSPEC sqrt (double x) ;}
其它对C++代码的修改见CMake教程
命令行使用示例 在项目目录下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 $ mkdir build $ cd build $ cmake .. $ cmake --build . Checking Build System Building Custom Rule E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/Step10/MathFunctions/CMakeLists.txt MakeTable.cxx MakeTable.vcxproj -> E:\Help\Other\CMake\CMake_Tutorial\guide\tutorial\Step10\build\Debug\MakeTable.exe Generating Table.h Building Custom Rule E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/Step10/MathFunctions/CMakeLists.txt mysqrt.cxx SqrtLibrary.vcxproj -> E:\Help\Other\CMake\CMake_Tutorial\guide\tutorial\Step10\build\Debug\SqrtLibrary.lib Building Custom Rule E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/Step10/MathFunctions/CMakeLists.txt MathFunctions.cxx 正在创建库 E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/Step10/build/Debug/MathFunctions.lib 和对象 E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/St ep10/build/Debug/MathFunctions.exp MathFunctions.vcxproj -> E:\Help\Other\CMake\CMake_Tutorial\guide\tutorial\Step10\build\Debug\MathFunctions.dll Building Custom Rule E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/Step10/CMakeLists.txt tutorial.cxx Tutorial.vcxproj -> E:\Help\Other\CMake\CMake_Tutorial\guide\tutorial\Step10\build\Debug\Tutorial.exe Building Custom Rule E:/Help/Other/CMake/CMake_Tutorial/guide/tutorial/Step10/CMakeLists.txt
5.10. 生成器表达式,条件判断 在上一步的基础上, 本节示例展示了:
在构建过程中计算生成器表达式值,以生成特定于每个构建配置的信息
生成器表达式有三类: 逻辑表达式、信息表达式和输出表达式(Logical, Informational, and Output expressions)
逻辑表达式: $<0:...>
的结果是空字符串,$<1:...>
的结果是“…”的内容。它们也可以嵌套。
生成器表达式通常用来按需添加编译标志
使用INTERFACE目标 在目标间传递属性
注: 本节示例初始代码在示例目录的Step10
子目录, 成果在Step11
子目录
核心代码更改 顶层CMakeLists.txt 的相应部分:
1 2 3 set (CMAKE_CXX_STANDARD 11 )set (CMAKE_CXX_STANDARD_REQUIRED True )
更改为:
1 2 3 4 5 6 7 8 9 10 add_library (tutorial_compiler_flags INTERFACE)target_compile_features (tutorial_compiler_flags INTERFACE cxx_std_11)set (gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>" )set (msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>" )target_compile_options (tutorial_compiler_flags INTERFACE "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>" "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>" )
库目录CMakeLists.txt 目标链接库代码:
1 target_link_libraries (MakeTable[SqrtLibrary|MathFunctions] PRIVATE[PUBLIC] tutorial_compiler_flags)
5.11. 添加导出配置,以支持find_package 在上一步的基础上, 本节示例展示了:
如何让其他项目方便地使用本项目
在install(TARGETS) 中使用EXPORT 关键字, 它用于将目标从安装树导入到另一个项目
生成MathFunctionsConfig.cmake , 以让find_package() 命令可以找到本项目
显式安装生成的MathFunctionsTargets.cmake
注: 本节示例初始代码在示例目录的Step11
子目录, 成果在Step12
子目录
核心代码更改 在MathFunctions/CMakeLists.txt 中增加EXPORT :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 target_include_directories (MathFunctions INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR} > $<INSTALL_INTERFACE:include > ) install (TARGETS MathFunctions tutorial_compiler_flags DESTINATION lib EXPORT MathFunctionsTargets) install (FILES MathFunctions.h DESTINATION include )
在顶层目录中添加Config.cmake.in , 用来生成MathFunctionsTargets.cmake :
1 2 3 @PACKAGE_INIT@ include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
在顶层CMakeLists.txt ,为了正确配置和安装MathFunctionsTargets.cmake , 添加以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 install (EXPORT MathFunctionsTargets FILE MathFunctionsTargets.cmake DESTINATION lib/cmake/MathFunctions ) include (CMakePackageConfigHelpers)configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR} /Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake" INSTALL_DESTINATION "lib/cmake/example" NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake" VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}" COMPATIBILITY AnyNewerVersion ) install (FILES ${CMAKE_CURRENT_BINARY_DIR} /MathFunctionsConfig.cmake DESTINATION lib/cmake/MathFunctions )
到这里,这是一个可以在项目安装或打包以后重定位的CMake配置。 如果需要项目在一个构建目录中使用,在顶层CMakeLists.txt 的结尾添加以下内容:
1 2 3 export (EXPORT MathFunctionsTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake" )
通过这个导出调用,我们现在生成一个Targets.cmake
,使得在构建目录中配置生成的MathFunctionsConfig.cmake
可以被其他项目使用,而不需要安装它。 此处未试验, 不理解
5.12. 将调试版和发行版打包在一起 在上一步的基础上, 本节示例展示了:
为调试版文件设置后缀: 非执行程序目标会根据CMAKE_DEBUG_POSTFIX 生成它的_POSTFIX
执行程序目录的DEBUG_POSTFIX 需要手工设置
注1: 本节示例初始代码在示例目录的Step12
子目录, 成果在Complete
子目录 注2: 本节打包工作在win10上没有成功
核心代码更改 在顶层CMakeLists.txt 中更改:
1 2 3 4 5 set (CMAKE_DEBUG_POSTFIX d)... set_target_properties (Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} )