官方教程:https://cmake.org/cmake/help/latest/guide/tutorial/index.html
一些总结:https://wangpengcheng.github.io/2019/08/13/learn_cmake/
最小配置的 CMakeLists.txt
# Set the minimum required version of CMake to be 3.10
cmake_minimum_required(VERSION 3.10)
# Create a project named Tutorial
project(Tutorial VERSION 1.0)
# set(Tutorial_VERSION_MAJOR 1)
# set(Tutorial_VERSION_MINOR 0)
# Set the variable CMAKE_CXX_STANDARD to 11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add an executable called Tutorial to the project
add_executable(Tutorial tutorial.cpp)
aux_source_directory(. DIR_SRCS)
将当前目录所有源文件的文件名赋值给变量 DIR_SRCS
,使用 add_executable(Tutorial ${DIR_SRCS})
可选:MacOS + gcc + clangd 最小配置
# Set the minimum required version of CMake to be 3.10
cmake_minimum_required(VERSION 3.10)
# Create a project named Tutorial
project(Tutorial VERSION 1.0)
# set(Tutorial_VERSION_MAJOR 1)
# set(Tutorial_VERSION_MINOR 0)
# Set the variable CMAKE_CXX_STANDARD to 11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# set -isysroot for macOS # default to macOS [according to gcc version]
if(APPLE)
set(CMAKE_OSX_SYSROOT /Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk)
set(CMAKE_OSX_DEPLOYMENT_TARGET 12.0) # [according to gcc built for macos version]
endif()
# Add an executable called Tutorial to the project
aux_source_directory(. DIR_SRCS)
add_executable(Tutorial ${DIR_SRCS})
项目中会生成 lib 库文件,并在其他部分可选的链接使用该库
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Tutorial VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
option(USE_MYMATH "Use tutorial provided math implementation" ON)
configure_file(TutorialConfig.h.in TutorialConfig.h)
if(USE_MYMATH)
add_subdirectory(MathFunctions) # 子目录会生成 MathFunctions lib
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES})
使用 option
命令,可以定义一个boolean变量
使用 configure_file
命令,将配置头文件,经过变量替换生成C++ header file:
@var@
变量,使用 CMakeLists.txt 中定义个变量进行替换;#cmakedefine
替换为 #define
,如果后面定义的boolean变量是 ON
则进行替换${PROJECT_BINARY_DIR}
目录,即 cmake 的 build 目录使用 if()
来控制添加 lib 生成,定义 EXTRA_LIBS 列表
,EXTRA_INCLUDES 列表
,默认为空
使用 target_link_libraries
对 target 链接指定的库
使用 target_include_directories
对 target 添加指定的头文件目录
说明:可以在配置项目时,指定 cmake .. -DUSE_MYMATH=OFF
来覆盖定义的值
INTERFACE
)对上一个 cmake 改进,之前的做法需要链接 lib
库文件,并且在上层中需要显示的指定库对应的 include 头文件目录,非常繁琐。
通过 Usage Requirements
来控制库在链接时的传递属性,使用 INTERFACE
来表达该语义:任意链接该库 target 必须 include 当前/指定的源目录(用于搜索头文件)。INTERFACE
表示消费者需要,但是生产者不需要。(对于库而言,生成的 lib target 不需要,但是需要链接该库的 target 必须包含指定的目录)
子目录生成 lib 并指定 Usage Requirements
的 CMakeLists.txt
:
add_library(MathFunctions mysqrt.cxx)
# Hint: Use target_include_directories with the INTERFACE keyword
# 尽管 MathFunctions 库不需要包含当前源目录,但是任何链接到 MathFunctions 的库都需要包含当前源目录
target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
top-level CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Tutorial VERSION 1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)
# add the MathFunctions library
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
endif()
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
# find TutorialConfig.h
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
生成器表达式,主要可以生成复杂的条件表达式,用于条件编译,条件链接等等。
例如,使用一个 interface library 来指定编译选项,使用生成器表达式对不同的编译器选择不同的编译选项:
cmake_minimum_required(VERSION 3.15)
# set the project name and version
project(Tutorial VERSION 1.0)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# * Creating an interface library called tutorial_compiler_flags
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
# Create helper variables to determine which compiler we are using
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
# With nested generator expressions, only use the flags for the build-tree
target_compile_options(tutorial_compiler_flags INTERFACE
"$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
"$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
configure_file(TutorialConfig.h.in TutorialConfig.h)
# add the MathFunctions library
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
endif()
# add the executable
add_executable(Tutorial tutorial.cxx)
# Link to tutorial_compiler_flags
target_link_libraries(Tutorial PUBLIC tutorial_compiler_flags ${EXTRA_LIBS})
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
使用生成器表达式,指定 cmake 最小版本为 3.15
使用 INTERFACE
来创建一个接口库,用于传递/指定 Usage Requirements
表达式:
$<COMPILE_LANG_AND_ID:CXX,...>
如果编译单元的语言是CXX,并且编译器ID与后面之一匹配,表达式为1否则为0$<BUILD_INTERFACE: STRING>
在相同build为STRING
,否则为空;上面的目的是:为了使得我们 installed project
的其他消费者不会继承编译选项;安装 executable | lib | headers
set(installable_libs MathFunctions tutorial_compiler_flags)
install(TARGETS ${installable_libs} DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include/MathFunc)
# bin file
install(TARGETS Tutorial DESTINATION bin)
构建和安装:
cmake --build .
cmake --install . --prefix "/home/myuser/installdir" # 有默认的位置,例如 /usr/local
或者
cmake --build . --target install
# enable testing
enable_testing()
# basic test, return value is zero
add_test(NAME Runs COMMAND Tutorial 25)
# verify that the output of the test contains certain strings.
add_test(NAME Correctness COMMAND Tutorial 4 )
set_tests_properties(Correctness PROPERTIES PASS_REGULAR_EXPRESSION "4 is 2")
# 定义函数 do_test 添加多个测试
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 a bunch of result based tests
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")
构建完成后,使用 ctest -VV
进行测试
例如测试系统是否支持某个库/函数:
# does this system provide the log and exp functions?
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <cmath>
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include <cmath>
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
根据测试结果,添加编译定义 target_compile_definitions()
其最终指令结果:g++ -DHAVE_EXP -DHAVE_LOG
在build开始可以先生成 output,用于后续的 target build:
add_executable(MakeTable MakeTable.cxx)
# add a custom command that specifies how to produce Table.h by running MakeTable.
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
build 会先指定自定义命令中的指定,生成 output 文件,在 cmake --build .
执行
【说明:在指定 add_library 等,可以指定依赖的头文件用于说明构建的依赖关系】
使用 CPack
将生成的二进制文件,库和头文件打包成压缩文件,并生成简易的提取安装脚本。
# 该模块将包括当前平台项目所需的任何运行时库
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}")
set(CPACK_SOURCE_GENERATOR "TGZ") # selects a file format for the source package
include(CPack)
构建 build 后,使用 cpack
打包即可,主要工作:
导入 InstallRequiredSystemLibraries 模块,以便之后导入 CPack 模块;
设置一些 CPack 相关变量,包括版权信息,版本信息,压缩格式;
导入 CPack 模块。
便于其他 CMake 项目可以复用我们的项目,无论是通过我们的构建目录、本地安装还是打包时。
行为:在构建目录build,本地安装(/usr/local/lib/cmake
)或者在打包的文件夹中生成cmake配置文件。
好处:不用特别指定项目/库的相关 include/lib 路径,方便使用(指定 package 目录)
生成的文件:
xxx.cmake
目标信息
xxxConfig.cmake
通过 Config.cmake.in
文件生成,以便 CMake **find_package()**
命令可以找到该项目(用于修改包的 PREFIX_DIR
路径)
xxxConfigVersion.cmake
记录软件包的版本和兼容性
使用package,例如打包后的目录为:
Tutorial-1.0-Darwin
├── bin
│ └── Tutorial
├── include
│ ├── MathFunctions.h
│ └── TutorialConfig.h
└── lib
├── cmake
│ └── MathFunctions
│ ├── MathFunctionsConfig.cmake
│ ├── MathFunctionsConfigVersion.cmake
│ ├── MathFunctionsTargets-noconfig.cmake
│ └── MathFunctionsTargets.cmake
├── libMathFunctions.dylib
└── libSqrtLibrary.a
使用非常方便:
list(APPEND CMAKE_PREFIX_PATH "${PROJECT_SOURCE_DIR}/Tutorial-1.0-Darwin")
find_package(MathFunctions REQUIRED)
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions) # no namespace
INTERFACE
自动包含链接库的头文件目录本文链接: cmake示例
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
发布日期: 2022-10-29
最新构建: 2024-12-26
欢迎任何与文章内容相关并保持尊重的评论😊 !