CMake 教程
1. 运行CMake
1.1 构建项目
在构建项目前建议创建一个build
目录,以下是一个经典的Cmake构建过程:
~/package $ mkdir build
~/package $ cd build
~/package/build $ cmake ..
~/package/build $ make
make
命令也可以使用cmake --build
来代替
以下任何一条命令都可以执行安装:
# From the build directory (pick one)
~/package/build $ make install
~/package/build $ cmake --build . --target install
~/package/build $ cmake --install . # CMake 3.15+ only
# From the source directory (pick one)
~/package $ make -C build install
~/package $ cmake --build build --target install
~/package $ cmake --install build # CMake 3.15+ only
1.2 选择编译器
选择编译器必须在第一次运行时在空的目录中进行,以clang编译器为例:
~/package/build $ CC=clang CXX=clang++ cmake ..
1.3 指定生成器
可以选择的构建工具有很多,make
工具通常是默认的。可以使用cmake --help
来查看系统支持的生成器
也可以使用-G"My tool"
选择构建工具,这同样需要在第一次运行Cmake之前就指定构建工具
可以使用环境变量CMAKE_GENERATOR
来控制默认的生成器
1.4 标准选项
以下是一些常用的cmake选项:
-DCMAKE_BUILD_TYPE=
从Release、RelWithDebInfo、Debug等参数中选择-DCMAKE_INSTALL_PREFIX=
安装位置,安装在UNIX系统中通常是/usr/local
,用户目录通常是~/.local
,或者也可以另选一个文件夹-DBUILD_SHARED_LIBS=
可以设置该选项为on
或off
来控制共享库的默认值-DBUILD_TESTING=
启用测试的常用名称
1.5 调试CMake文件
可以使用-trace
选项来打印CMake运行的每一行,由于它过于冗长,CMake 3.7 添加了 --trace-source="filename"
选项,这可以打印出想看的特定文件运行时执行的每一行。
2. CMake基础知识
2.1 最低版本要求
这是每个 CMakeLists.txt
都必须包含的第一行:
cmake_minimum_required(VERSION 3.1)
从CMake 3.12开始,版本号可以声明为一个范围,如VERSION 3.1...3.15
,这意味着这个工程最低可以支持3.1版本,最高可以支持3.15版本
当开始一个新的项目时,推荐这样写:
cmake_minimum_required(VERSION 3.7...3.21)
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
当CMake的版本低于3.12时,则CMake将会被设置为当前的版本
2.2 设置一个项目
每个顶层CMakeLists文件都应当有类似下面这行:
project(MyProject VERSION 1.0
DESCRIPTION "Very nice project"
LANGUAGES CXX)
这行表面项目的名称为MyProject,项目版本号为1.0,项目描述是"Very nice project",项目的语言为CXX(可以是C、CXX、Fortran、ASM、CUDA、SWIFT)
2.3 生成一个可执行文件
add_executable(one two.cpp three.h)
one是生成的可执行文件的名称,也是想创建的CMake目标的名称;two.cpp是源文件的列表,可以添加多个;three.h是头文件,通常可以忽略
2.4 生成一个库
add_library(one STATIC two.cpp three.h)
生成一个库时,可以选择库的类型,可以是 STATIC
, SHARED
或者MODULE
,如果不选择,CMake将会通过BUILD_SHARED_LIBS
的值来选择构建STATIC
还是SHARED
类型的库
2.5 指定目标信息
target_include_directories(one PUBLIC include)
为目标one包含一个目录include,PUBLIC
对于二进制目标没有什么含义,但是对于库来说,它让CMake知道,任何链接到这个目标的目标也必须包含这个目录,其他选项还有PRIVATE
以(只影响当前目标,不影响依赖)及INTERFACE
(只影响依赖)
将目标链接起来:
add_library(another STATIC another.cpp another.h)
# 将one库链接到目标another
target_link_libraries(another PUBLIC one)
cmake_minimum_required(VERSION 3.8)
project(Calculator LANGUAGES CXX)
add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)
target_include_directories(calclib PUBLIC include)
target_compile_features(calclib PUBLIC cxx_std_11)
add_executable(calc apps/calc.cpp)
target_link_libraries(calc PUBLIC calclib)
3. 变量与缓存
3.1 本地变量
声明本地变量的方式如下:
set(MY_VARIBALE "value")
变量名通常全部用大写,变量值跟在其后。可以通过 ${}
来解析一个变量,例如 ${MY_VARIABLE}
CMake有作用域的概念,在声明一个变量后,只可以在它的作用域内访问这个变量。
列表就是包含一系列变量:
set(MY_LIST "one;two")
需要注意的是,在 CMake 中如果一个值没有空格,那么加和不加引号的效果是一样的。
3.2 缓存变量
CMake 提供了一个缓存变量来允许从命令行中设置变量。CMake 中已经有一些预置的变量,像 CMAKE_BUILD_TYPE
。如果一个变量还没有被定义,可以这样声明并设置它:
set(MY_CACHE_VARIABLE "VALUE" CACHE STRING "Description")
# 定义声明缓存变量时可以不使用加上FORCE
修改缓存变量:
set(MY_CACHE_VARIABLE "MODIFIED" CACHE STRING "MODIFY VARIABLE")
3.3 环境变量
可以通过 set(ENV{variable_name} value)
和 $ENV{variable_name}
来设置和获取环境变量
3.4 缓存
缓存实际上就是个文本文件CMakeCache.txt
,当运行 CMake 构建目录时会创建它。 CMake 可以通过它来记住设置的所有东西,因此可以不必在重新运行 CMake 的时候再次列出所有的选项。
3.5 属性
CMake 也可以通过属性来存储信息。这就像是一个变量,但它被附加到一些其他的物体 ( item ) 上,像是一个目录或者是一个目标。一个全局的属性可以是一个有用的非缓存的全局变量。许多目标属性都是被以 CMAKE_
为前缀的变量来初始化的。
set_property(TARGET TargetName
PROPERTY CXX_STANDARD 11)
set_target_properties(TargetName PROPERTIES
CXX_STANDARD 11)
4. 流程控制
CMake的if
语句:
if(variable)
# If variable is `ON`, `YES`, `TRUE`, `Y`, or non zero number
else()
# If variable is `0`, `OFF`, `NO`, `FALSE`, `N`, `IGNORE`, `NOTFOUND`, `""`, or ends in `-NOTFOUND`
endif()
# If variable does not expand to one of the above, CMake will expand it then try again
if语句中的条件既可以是变量名,也可以是使用${}
进行解析
if("${variable}") # 注意这里加了引号,防止多次解析
# True if variable is not false-like
else()
# Note that undefined variables would be `""` thus false
endif()
if条件还可以使用一些关键字,例如:
- 一元的:
NOT
,TARGET
,EXISTS
(文件),DEFINED
, 等。 - 二元的:
STREQUAL
,AND
,OR
,MATCHES
( 正则表达式 ),VERSION_LESS
,VERSION_LESS_EQUAL
( CMake 3.7+ ), 等。
5. 宏定义与函数
CMake可以定义自己的函数和宏 function
或 macro
。函数和宏只有作用域上存在区别,宏没有作用域的限制。所以说,如果你想让函数中定义的变量对外部可见,你需要使用 PARENT_SCOPE
来改变其作用域。
一个简单函数示例:
function(SIMPLE REQUIRED_ARG)
message(STATUS "Simple arguments: ${REQUIRED_ARG}, followed by ${ARGN}")
set(${REQUIRED_ARG} "From SIMPLE" PARENT_SCOPE)
endfunction()
simple(This Foo Bar)
message("Output: ${This}")
一个简单宏示例:
macro(macro1)
message(STATUS "macro1 called!")
endmacro()
macro1()
函数和宏的所有参数都会被存储在ARGN
这个变量中
标签:教程,cmake,变量,package,VERSION,build,CMake From: https://www.cnblogs.com/N1rv2na/p/18277723注意:函数名和宏名并不区分大小写!