Cmake构建系统的使用


一、速查手册

1. 常用命令

命令作用
cmake …使用默认参数执行构建
cmake -D CMAKE_BUILD_TYPE=Debug …构建带调试信息的程序或库
cmake -G Ninja …指定生成器为Ninja
cmake --build .根据默认构建系统生成程序
cmake -version查看cmake版本
  • -B 用于指定构建目录
  • -D 用于定义Cmake变量
  • -E 调用Cmake内置命令的参数
  • -G 用于指定生成器
  • -S 用于指定源代码目录,此目录包含了CMakeLists.txt 文件

2. 常用变量

变量名含义
CMAKE_SOURCE_DIR最顶层CmakeLists.txt所在目录,CHAN
CMAKE_CURRENT_SOURCE_DIR当前CMakeLists.txt 所在路径
PROJECT_SOURCE_DIR工程的根目录
CMAKE_ARCHIVE_OUTPUT_DIRECTORY静态库的输出目录
CMAKE_LIBRARY_OUTPUT_DIRECTORY动态库的输出目录
CMAKE_RUNTIME_OUTPUT_DIRECTORY可执行文件的输出路径

3. 基本模板

cmake_minimum_required (VERSION 3.5)
 
project (Test)

# 设置头文件目录
include_directories(${PROJECT_SOURCE_DIR}/inc INC_DIR)

# 设置源文件目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_DIR)

# 添加可执行文件
add_executable(helloworld hello.cpp)

# 链接库
target_link_libraries(helloworld ${CMAKE_SOURCE_DIR}/add.a)
cmake_minimum_required (VERSION 3.5)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_BUILD_TYPE)
	set(CMAKE_BUILD_TYPE Release)
endif()

project (Test)
# 设置头文件目录
include_directories(${PROJECT_SOURCE_DIR}/inc INC_DIR)

# 设置源文件目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_DIR)

# 添加可执行文件
add_executable(helloworld hello.cpp)

# 链接库
target_link_libraries(helloworld ${CMAKE_SOURCE_DIR}/add.a)

二、基本用法

1. 单个源文件

1.1 目录结构

.
├── build
├── CMakeLists.txt
└── hello.cpp

1.2 CmakeLists.txt

cmake_minimum_required (VERSION 3.5)
 
project (LearnCmake)
 
add_executable(helloworld hello.cpp)

1.3 编译步骤

cd build
cmake ..
make

2. 多个源文件

2.1 目录结构

Project
├── build
├── add.cpp
├── add.hpp
├── CMakeLists.txt
└── hello.cpp

2.2 CmakeLists.txt

cmake_minimum_required (VERSION 3.5)
 
project (LearnCmake)
 
add_executable(helloworld hello.cpp add.cpp)

2.3 编译步骤

cd build
cmake ..
make

3. 编译动态库

3.1 目录结构

├── build
├── CMakeLists.txt
├── hello.cpp
├── hello.hpp
└── main.cpp

3.2 CmakeLists.txt

cmake_minimum_required (VERSION 3.5)
 
project (LearnCmake)

# 创建共享库目标
add_library(hello SHARED hello.hpp hello.cpp) 

# 设置库的最终生成路径
set(LIBRARY_OUTPUT_PATH ./lib)

3.3 编译步骤

cd build
cmake ..
make

4. 编译静态库

4.1 目录结构

Project
├── build
├── CMakeLists.txt
├── hello.cpp
├── hello.hpp
└── main.cpp

4.2 CmakeLists.txt

cmake_minimum_required (VERSION 3.5)
 
project (LearnCmake)

# 创建共享库目标
add_library(hello STATIC hello.hpp hello.cpp) 

# 设置库的最终生成路径
set(LIBRARY_OUTPUT_PATH ./lib)

4.3 编译步骤

cd build
cmake ..
make

5. 综合案例

5.1 目录结构

Project
├── build
├── CMakeLists.txt
├── hello.cpp
├── hello.hpp
└── main.cpp

5.2 CmakeLists.txt

# 设置最低版本
cmake_minimum_required (VERSION 3.5)

# 设置项目名称
project (LearnCmake)

# 设置头文件目录
include_directories(${PROJECT_SOURCE_DIR}/inc INC_DIR)

# 设置源文件目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_DIR)

# 创建共享库目标
add_library(hello_shared SHARED ${SRC_DIR}) 

# 创建静态库目标
add_library(hello_static STATIC ${SRC_DIR}) 


# 设置库的最终生成路径
set(LIBRARY_OUTPUT_PATH ../lib)

# 创建可执行文件
add_executable(main main.cpp)

# 链接库文件
target_link_libraries(main hello_static)

5.3 编译步骤

mkdir -p build
cd build
cmake ..
cmake --build .

三、进阶用法

1. 编译选项

有时因为一些特殊需要,为了实现自定义的编译,我们需要指定编译选项,这时我们可使用 add_compile_options 来添加编译选项,如下:

add_compile_options(-std=c++11 -Wall)

2. 控制选项

有时希望在编译代码时只编译一些指定的源码,可以使用cmake的option命令,主要遇到的情况分为2种:

  • 本来要生成多个bin或库文件,现在只想生成部分指定的bin或库文件
  • 对于同一个bin文件,只想编译其中部分代码(使用宏来控制)

3. 设置目录

  • aux_source_directory(dir var) 可把dir目录中的所有源文件都储存在var变量中
  • include_directories ( dir ) ,其作用类似gcc中的 gcc -I dir

设置指定头文件及源文件目录的示例CMakeLists.txt文件如下:

# 设置最低版本
cmake_minimum_required (VERSION 3.5)

# 设置项目名称
project (LearnCmake)						

# 设置头文件目录
include_directories(./include1 ./include2)

# 设置源文件目录
aux_source_directory(src1 SRC1_DIR)
aux_source_directory(src2 SRC2_DIR)
aux_source_directory(main MAIN_DIR)

# 生成可执行文件
add_executable(helloworld ${SRC1_DIR} ${SRC2_DI} ${MAIN_DIR})

4. 编译类型

1. Debug: `-O0 -g`
2. Release: `-O3 -DNDEBUG`
3. MinSizeRel: `-Os -DNDEBUG`
4. RelWithDebInfo: `-O2 -g -DNDEBUG`

4.1 C编译标志相关变量

CMAKE_C_FLAGS
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]

4.2 C++编译标志相关变量

CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]

CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]或 CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO] 则指定特定构建类型的编译标志,这些编译标志将被加入到 CMAKE_C_FLAGS 或 CMAKE_CXX_FLAGS 中去,例如,如果构建类型为 DEBUG,那么 CMAKE_CXX_FLAGS_DEBUG 将被加入到 CMAKE_CXX_FLAGS中去

4.3 链接标志相关变量

CMAKE_EXE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_MODULE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_SHARED_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
它们类似于编译标志相关变量

debug版的项目生成的可执行文件需要有调试信息并且不需要进行优化,而release版的不需要调试信息但需要优化。这些特性在gcc/g++中是通过编译时的参数决定的,如果将优化程度调到最高需要设置-O3,最低-O0即不做优化;添加调试信息的参数是-g -ggdb,如果不添加这个参数,调试信息就不会被包含在生成的二进制文件中。

CMake中有一个变量CMAKE_BUILD_TYPE,可以的取值是Debug、Release、RelWithDebInfo和MinSizeRel。当这个变量值为Debug的时候,CMake会使用变量CMAKE_CXX_FLAGS_DEBUG和 CMAKE_C_FLAGS_DEBUG中的字符串作为编译选项生成Makefile ,当这个变量值为 Release 的时候,工程会使用变量 CMAKE_CXX_FLAGS_RELEASE 和CMAKE_C_FLAGS_RELEASE 选项生成 Makefile。

project(main)
cmake_minimum_required(version 2.6)
set(CMAKE_SOURCE_DIR .)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")	# 设置debug编译选项
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")			# 设置release编译选项
ADD_EXECUTABLE(main ${DIR_SRCS})
AUX_SOURCE_DIRECTORY(. DIR_SRCS)

四、语法规则

Cmake的指令是大小写无关的,但建议全部使用大写指令。

1. 注释

单行注释

# 注释内容

多行注释

# [[
注释内容
]]

2. 变量

Cmake中所有的变量都是string类型

set(变量名 变量值)   # 声明一个变量 
unset(变量)		 # 移除一个变量
${变量名}			 # 引用变量
message("变量名=${变量名}")	# 打印一个变量值

3. 列表

列表也是字符串,可以把列表看作是一个特殊的变量,这个变量包含多个值,其语法格式如下:

set(列表名 值1 值2 值3 ...)    # 方式一
set(列表名 "值1;值2;值3;...")  # 方式二

引用列表和打印列表与变量的使用方式相同

${列表名}			 		  # 引用列表
message("列表名=${列表名}")	# 打印列表

4. 作用域

  • 全局层:cache变量,在整个项目范围可见。一般在set定义变量时,需要指定CACHE参数才能定义为cache变量
  • 目录层:在当前目录的CMakeList.txt中定义,以及在该文件包含的其他CMake源文件中定义的变量
  • 函数层:在命令函数中定义的变量,属于函数作用域内的变量

5. 判断语句

在 CMake 中,可以使用 if 语句来进行条件判断。CMake 提供了多种条件判断操作符和函数,用于比较字符串、数值、文件属性等。

5.1 比较操作符

CMake的比较操作符如下:

  • EQUAL:检查是否相等
  • LESS:检查是否小于
  • GREATER:检查是否大于
  • LESS_EQUAL:检查是否小于或等于
  • GREATER_EQUAL:检查是否大于或等于
  • STREQUAL:检查字符串是否相等
  • STRLESS:检查字符串是否小于(按字典顺序)
  • STRGREATER:检查字符串是否大于(按字典顺序)
  • EXISTS:检查文件或目录是否存在
  • IS_DIRECTORY:检查是否是目录
  • IS_SYMLINK:检查是否是符号链接
  • IS_ABSOLUTE:检查路径是否是绝对路径

5.2 逻辑操作符

  • AND:逻辑与
  • OR:逻辑或
  • NOT:逻辑非

5.3 使用示例

以下是 CMake 中条件判断语句的详细介绍和示例。

if(condition)
    # Commands to execute if the condition is true
elseif(another_condition)
    # Commands to execute if the another condition is true
else()
    # Commands to execute if none of the above conditions are true
endif()

示例代码如下:

# 字符串比较
if(variable STREQUAL "value")
    message(STATUS "Variable equals 'value'")
endif()

# 数值比较
if(variable EQUAL 10)
    message(STATUS "Variable equals 10")
elseif(variable GREATER 10)
    message(STATUS "Variable is greater than 10")
else()
    message(STATUS "Variable is less than 10")
endif()

# 文件目录检查
if(EXISTS "path/to/file_or_directory")
    message(STATUS "File or directory exists")
endif()
if(IS_DIRECTORY "path/to/directory")
    message(STATUS "It is a directory")
endif()
if(IS_SYMLINK "path/to/symlink")
    message(STATUS "It is a symbolic link")
endif()

# 逻辑操作
if(variable AND another_variable)
    message(STATUS "Both variables are true")
endif()
if(variable OR another_variable)
    message(STATUS "At least one of the variables is true")
endif()
if(NOT variable)
    message(STATUS "Variable is false")
endif()

更加复杂的示例如下:
操作系统检测

cmake_minimum_required(VERSION 3.0)
project(OSDetection)

if(WIN32)
    message(STATUS "This is Windows")
elseif(UNIX)
    message(STATUS "This is Unix or Unix-like (including Linux and macOS)")
    if(APPLE)
        message(STATUS "This is macOS")
    else()
        message(STATUS "This is Linux or another Unix-like system")
    endif()
else()
    message(STATUS "Unknown operating system")
endif()

C++标准支持

cmake_minimum_required(VERSION 3.0)
project(CppStandardCheck)

set(CMAKE_CXX_STANDARD 11)

if(CMAKE_CXX_STANDARD EQUAL 11)
    message(STATUS "Using C++11")
elseif(CMAKE_CXX_STANDARD EQUAL 14)
    message(STATUS "Using C++14")
elseif(CMAKE_CXX_STANDARD EQUAL 17)
    message(STATUS "Using C++17")
else()
    message(STATUS "Using an unknown or unsupported C++ standard")
endif()

配置选项和条件编译

cmake_minimum_required(VERSION 3.0)
project(ConfigOptions)

option(USE_FEATURE_X "Enable feature X" OFF)
option(USE_FEATURE_Y "Enable feature Y" ON)

if(USE_FEATURE_X)
    add_definitions(-DUSE_FEATURE_X)
    message(STATUS "Feature X enabled")
endif()

if(USE_FEATURE_Y)
    add_definitions(-DUSE_FEATURE_Y)
    message(STATUS "Feature Y enabled")
endif()

6. 循环语句

6.1 foreach

用于遍历列表中的每个元素或特定范围的值。

# 遍历一组数值
foreach(v arg1 arg2 ...)
    # Commands to execute for each element
endforeach()
# 遍历列表变量
foreach(v IN LISTS list_var)
    # Commands to execute for each element in list_var
endforeach()

示例如下

cmake_minimum_required(VERSION 3.0)
project(ForeachExample)

foreach(i 1 2 3 4 5)
    message(STATUS "Number: ${i}")
endforeach()

set(my_list a b c d e)
foreach(item IN LISTS my_list)
    message(STATUS "Item: ${item}")
endforeach()

6.2 while

用于在给定条件为真时重复执行命令。它的基本用法如下:

while(condition)
    # Commands to execute while condition is true
endwhile()

示例如下:

cmake_minimum_required(VERSION 3.0)
project(WhileExample)

set(i 0)
while(i LESS 5)
    message(STATUS "Number: ${i}")
    math(EXPR i "${i} + 1")
endwhile()

7. 定义函数

在 CMake 中,可以使用 function 关键字来定义函数。函数允许你封装一段逻辑,以便在多个地方重复使用。定义函数的基本语法如下:

function(FunctionName arg1 arg2 ...)
    # Commands that the function executes
endfunction()

示例如下:

cmake_minimum_required(VERSION 3.0)
project(FunctionExample)

# 定义普通函数
function(PrintMessage msg)
    message(STATUS "Message: ${msg}")
endfunction()
# 调用函数
PrintMessage("Hello, World!")
PrintMessage("This is a custom function in CMake.")


# 定义带有默认值的函数
function(PrintWithPrefix msg prefix)
    if(NOT prefix)
        set(prefix "DefaultPrefix")
    endif()
    message(STATUS "${prefix}: ${msg}")
endfunction()
# 调用函数
PrintWithPrefix("Hello, World!" "Greeting")
PrintWithPrefix("This is a message without a prefix")

# 定义函数并设置返回值
function(AddNumbers a b result)
    math(EXPR sum "${a} + ${b}")
    set(${result} ${sum} PARENT_SCOPE)
endfunction()
# 调用函数并获取返回值
AddNumbers(3 4 result)
message(STATUS "The sum is: ${result}")

# 定义处理列表的函数
function(PrintList mylist)
    foreach(item IN LISTS mylist)
        message(STATUS "Item: ${item}")
    endforeach()
endfunction()
# 调用函数
set(mylist a b c d e)
PrintList(mylist)

8. 定义宏

9. 预设变量

变量作用
CMAKE_MAJOR_VERSIONcmake 主版本号
CMAKE_MINOR_VERSIONcmake 次版本号
CMAKE_C_FLAGS设置 C 编译选项
CMAKE_CXX_FLAGS设置 C++ 编译选项
PROJECT_SOURCE_DIR工程的根目录
PROJECT_BINARY_DIR运行 cmake 命令的目录
CMAKE_CURRENT_SOURCE_DIR当前CMakeLists.txt 所在路径
CMAKE_CURRENT_BINARY_DIR目标文件编译目录
EXECUTABLE_OUTPUT_PATH重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH重新定义目标链接库文件的存放位置
UNIX如果为真,表示为UNIX-like的系统,包括AppleOSX和CygWin
WIN32如果为真,表示为 Windows 系统,包括 CygWin
APPLE如果为真,表示为 Apple 系统
CMAKE_SIZEOF_VOID_P表示void*的大小(例如为4或者8),可以使用其来判断当前构建为32位还是64位
CMAKE_CURRENT_LIST_DIR表示正在处理的CMakeLists.txt文件所在目录的绝对路径
CMAKE_ARCHIVE_OUTPUT_DIRECTORY用于设置ARCHIVE目标的输出路径
CMAKE_LIBRARY_OUTPUT_DIRECTORY用于设置LIBRARY目标的输出路径
CMAKE_RUNTIME_OUTPUT_DIRECTORY用于设置RUNTIME目标的输出路径
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值