CMake常用命令

1. 概念

CMake 是一个跨平台的开源构建系统,它被设计用来控制软件的编译过程,使用与编译器无关的配置文件来生成本地的构建文件。简单来说,就是用简单的语法告诉编译器要怎么编译、编译哪些文件。
CMake 支持多种编译器和操作系统,可以支持包括 Windows、Linux、macOS 以及各种嵌入式系统,也可以使用不同的编译器,比如 GCC、Clang、MSVC 等,生成如 Makefile、Visual Studio 项目文件等各种构建工具所需的配置文件。

一个简单的 CMake 使用流程如下:
(1)编写 CMakeLists.txt:在项目的根目录和子目录中编写 CMakeLists.txt 文件,描述项目的构建规则。
(2)配置项目:在项目根目录中运行 cmake 命令,生成本地构建系统的配置文件(例如 Makefile 或 Visual Studio 项目文件)。
(3)构建项目:使用生成的构建文件运行构建工具(如 make 或 Visual Studio),编译项目。

假设一个简单的项目结构如下:

MyProject/
├── CMakeLists.txt
├── main.cpp
└── include/
    └── myheader.h

可以编写出如下简单的CMake文件:

cmake_minimum_required(VERSION 3.10)

# 设置项目名称和版本
project(MyProject VERSION 1.0)

# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 包含头文件目录
include_directories(${PROJECT_SOURCE_DIR}/include)

# 添加可执行文件
add_executable(MyProject main.cpp)

运行以下命令配置和构建项目:

mkdir build
cd build
cmake ..
make

2. 常见命令

命令格式:

command_name(arg1 arg2 ... argN)

注释:

# 这是注释

(1) cmake_minimum_required

指定 CMake 的最低版本要求,不同版本的 CMake 可能会有不同的特性和行为。通过指定最低版本,可以确保项目在构建时使用期望的 CMake 特性和行为。

cmake_minimum_required(VERSION 3.10)

版本后面加FATAL_ERROR,明确指定在版本不满足时立即停止处理并报错

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(HelloProject)

(2)project

指定了项目的版本、描述、主页 URL,并指定它使用 C 和 C++ 语言

cmake_minimum_required(VERSION 3.10)
project(MyProject
    VERSION 1.2.3
    DESCRIPTION "This is a sample project"
    HOMEPAGE_URL "https://www.example.com"
    LANGUAGES C CXX)

(3)set

set 命令是 CMake 中最常用的命令之一,用于定义和修改变量。变量可以包含字符串、路径、列表等数据类型。

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
用法示例
基本赋值set(MY_VAR “Hello, World!”)
设置列表(CMake的列表元素仅支持字符串)set(MY_LIST “value1” “value2” “value3”)
设置变量(这个常用于设置常用的路径)# 定义变量 SRC_DIR 来存储 src 文件夹的路径
set(SRC_DIR “${CMAKE_SOURCE_DIR}/src”)
使用设置的变量# 设置源文件列表
set(SOURCES “${SRC_DIR}/other_source.cpp”)
缓存变量(示例将变量 MY_CACHE_VAR 存储在缓存中,类型为 STRING,并提供了描述。)set(MY_CACHE_VAR “default_value” CACHE STRING “This is a cached variable”)
覆盖缓存变量set(MY_CACHE_VAR “new_value” CACHE STRING “This is a cached variable” FORCE)

(4)include_directories

用于指定头文件搜索路径的命令。它告诉编译器在编译源文件时应该在哪里查找头文件。这样可以确保编译器能够找到并正确引用项目中的所有头文件。

include_directories(${PROJECT_SOURCE_DIR}/include)

使用 SYSTEM 标记
如果有一些第三方库的头文件目录,并且希望编译器忽略这些头文件中的警告,可以使用 SYSTEM 标记:

include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/third_party/include)

${CMAKE_SOURCE_DIR} 是 CMake 的一个内置变量,表示项目的根目录。

(5)add_executable

这个命令告诉 CMake 生成一个可执行文件,并指定生成该可执行文件所需的源文件。
基本语法:

add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
  • name:可执行文件的名称。
  • WIN32:指定在 Windows 上创建一个窗口应用程序,而不是控制台应用程序。这意味着不会自动链接控制台子系统。
  • MACOSX_BUNDLE:在 macOS 上创建一个应用程序包(bundle)。
  • EXCLUDE_FROM_ALL:指定目标不应默认包含在 ALL 构建中。
    source1, source2, …:生成可执行文件所需的源文件列表。

基本用法:

cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 指定源文件
set(SOURCES
    src/main.cpp
    src/helper.cpp
)

# 添加可执行文件
add_executable(MyExecutable ${SOURCES})

有时候如果忘记添加某个cpp文件,会有“undefined reference to”的报错,原因是某些执行的函数没有被编译进去,找不到就出现未定义报错了。

使用 WIN32
在 Windows 上创建一个窗口应用程序。

add_executable(MyWinApp WIN32 src/main.cpp src/helper.cpp)

使用MACOSX_BUNDLE
在 macOS 上创建一个应用程序包

add_executable(MyMacApp MACOSX_BUNDLE src/main.cpp src/helper.cpp)

使用 EXCLUDE_FROM_ALL
有时候,可能有一些辅助工具或测试程序,不希望每次构建主项目时都被构建。使用 EXCLUDE_FROM_ALL 可以避免这些目标在默认构建过程中被构建。
假设有如下结构的项目文件:

project_root/
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   ├── helper.cpp
│   └── helper.h
├── tools/
│   └── my_tool.cpp

不希望 辅助工具MyTool 在默认构建过程中被构建。

cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 指定源文件
set(SOURCES
    src/main.cpp
    src/helper.cpp
)

# 添加主可执行文件
add_executable(MyExecutable ${SOURCES})

# 添加辅助工具,但不包含在默认构建中
add_executable(MyTool EXCLUDE_FROM_ALL tools/my_tool.cpp)

(6)add_library

这个命令告诉 CMake 生成一个静态库或动态库,并指定生成该库所需的源文件。

add_library(MyLibrary mylibrary.cpp)

更完整的示例:

cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 指定源文件
set(LIB_SOURCES
    src/mylib/mylib.cpp
)

# 添加静态库
add_library(MyLib STATIC ${LIB_SOURCES})

# 指定可执行文件的源文件
set(EXEC_SOURCES
    src/main.cpp
)

# 添加可执行文件
add_executable(MyExecutable ${EXEC_SOURCES})

# 链接库
target_link_libraries(MyExecutable PRIVATE MyLib)

其中添加静态库时,用SHARED和MODULE替代STATIC,分别表示生成动态库、模块库。
如果希望某个库不包含在默认的 ALL 构建中,可以使用 EXCLUDE_FROM_ALL:

add_library(MyExcludedLib STATIC EXCLUDE_FROM_ALL src/mylib/mylib.cpp)

(7)target_link_libraries

用于指定目标(如可执行文件或库)需要链接的库的命令。它是管理项目依赖关系和链接库的关键命令之一。

target_link_libraries(MyProject MyLibrary)

target_link_libraries 支持三种作用域:

  • PRIVATE: 目标私有的链接库,只有目标本身需要这些库,其他依赖该目标的目标不需要。
  • PUBLIC: 目标公开的链接库,目标本身和依赖该目标的目标都需要这些库。
  • INTERFACE: 仅对依赖该目标的目标可见,目标本身不需要这些库。
# 仅 MyExecutable 需要 LibA 和 LibB
target_link_libraries(MyExecutable PRIVATE LibA LibB)
# MyExecutable 和依赖 MyExecutable 的目标都需要 LibA 和 LibB
target_link_libraries(MyExecutable PUBLIC LibA LibB)
# 仅依赖 MyExecutable 的目标需要 LibA 和 LibB,MyExecutable 本身不需要
target_link_libraries(MyExecutable INTERFACE LibA LibB)

(8)file

file 命令是 CMake 中一个非常强大的命令,用于执行各种文件操作。它可以用于创建目录、拷贝文件、读取文件内容、写入文件、检查文件属性等。下面详细介绍 file 命令的不同子命令及其用法。
以下是一个综合示例:

# 将内容写入指定的文件。如果文件不存在,会创建文件;如果文件存在,会覆盖文件内容
file(WRITE ${CMAKE_BINARY_DIR}/output.txt "Hello, World!")

# 将内容追加到指定文件的末尾。如果文件不存在,会创建文件
file(APPEND ${CMAKE_BINARY_DIR}/output.txt "\nAppended text.")

# 读取文件内容,并将其存储在指定变量中
file(READ ${CMAKE_SOURCE_DIR}/input.txt file_content)
message(STATUS "File content: ${file_content}")

# 使用通配符模式匹配文件,并将匹配的文件列表存储在指定变量中
file(GLOB source_files ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(MyProject ${source_files}) 

# 递归地使用通配符模式匹配文件,并将匹配的文件列表存储在指定变量中
file(GLOB_RECURSE all_headers ${CMAKE_SOURCE_DIR}/include/*.h)

# 创建指定的目录及其父目录。如果目录已经存在,则不会有任何操作
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/new_folder)

# 删除指定的文件
file(REMOVE ${CMAKE_BINARY_DIR}/output.txt)

# 递归地删除指定的目录及其内容
file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/old_folder)

# 重命名文件或目录
file(RENAME ${CMAKE_BINARY_DIR}/old_name.txt ${CMAKE_BINARY_DIR}/new_name.txt)

# 复制文件或目录到指定的目标位置
file(COPY ${CMAKE_SOURCE_DIR}/data DESTINATION ${CMAKE_BINARY_DIR})

# 将系统路径转换为 CMake 路径格式(使用正斜杠 / 作为路径分隔符)
file(TO_CMAKE_PATH "C:\\Program Files\\MyApp" cmake_path)
message(STATUS "CMake path: ${cmake_path}")

# 将 CMake 路径格式转换为本地系统路径格式
file(TO_NATIVE_PATH "/usr/local/bin" native_path)
message(STATUS "Native path: ${native_path}")

(9)foreach

foreach 命令是 CMake 中用于迭代列表或范围的控制结构。它允许对列表中的每个元素或范围内的每个值执行一系列命令。

cmake_minimum_required(VERSION 3.10)
project(ForeachExample)

# 迭代列表中的每个元素
set(my_list "apple" "banana" "cherry")
foreach(fruit ${my_list})
    message(STATUS "Fruit: ${fruit}")
endforeach()

# 迭代范围内的每个值
foreach(i RANGE 1 5)
    message(STATUS "Value: ${i}")
endforeach()

# 迭代范围内的每个值,指定步长
foreach(i RANGE 1 10 2)
    message(STATUS "Value with step: ${i}")
endforeach()

# 迭代变量中的每个元素
set(my_other_list "dog;cat;mouse")
foreach(animal IN LISTS my_other_list)
    message(STATUS "Animal: ${animal}")
endforeach()

# 直接指定元素
foreach(color red green blue)
    message(STATUS "Color: ${color}")
endforeach()

(10)if/else

if 和 else 语句用于条件控制流。我们可能需要根据不同的编译器、操作系统或用户选项来调整构建过程。
根据变量值执行不同的命令:

set(MY_VARIABLE TRUE)

if(MY_VARIABLE)
  message(STATUS "MY_VARIABLE is TRUE")
else()
  message(STATUS "MY_VARIABLE is FALSE")
endif()

根据编译器类型设置编译选项

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
else()
  message(WARNING "Unknown compiler, using default flags")
endif()

检查文件是否存在

if(EXISTS "${CMAKE_SOURCE_DIR}/config.h")
  message(STATUS "config.h exists")
else()
  message(WARNING "config.h does not exist")
endif()

组合条件

if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  message(STATUS "Using GCC on Linux")
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  message(STATUS "Building on Windows or macOS")
endif()

(11)字符串处理

CMake 提供了丰富的字符串处理功能,通过这些命令,你可以方便地进行字符串的各种操作,如连接、替换、匹配、转换大小写等。这些功能在编写复杂的 CMake 配置文件时非常有用。

cmake_minimum_required(VERSION 3.10)
project(StringProcessingExample)

# 定义一个字符串
set(MY_STRING "   Hello, CMake World!   ")

# 去除前后空格
string(STRIP "${MY_STRING}" STRIPPED_STRING)
message(STATUS "Stripped: '${STRIPPED_STRING}'")

# 追加字符串
string(APPEND MY_STRING "!!")
message(STATUS "${MY_STRING}")

# 转换为大写(TOUPPER)/小写(TOLOWER)
string(TOUPPER "${STRIPPED_STRING}" UPPER_STRING)
message(STATUS "Upper: '${UPPER_STRING}'")

# 替换子字符串
string(REPLACE "CMAKE" "CMake" REPLACED_STRING "${UPPER_STRING}")
message(STATUS "Replaced: '${REPLACED_STRING}'")

# 提取子字符串
string(SUBSTRING "${REPLACED_STRING}" 7 5 SUBSTRING_VAR)
message(STATUS "Substring: '${SUBSTRING_VAR}'")

# 获取字符串长度
string(LENGTH "${REPLACED_STRING}" LENGTH_VAR)
message(STATUS "Length: ${LENGTH_VAR}")

# 使用正则表达式匹配
string(REGEX MATCH "CMake" MATCH_VAR "${REPLACED_STRING}")
message(STATUS "Regex Match: '${MATCH_VAR}'")

# 使用正则表达式替换字符串中的子字符串
string(REGEX REPLACE "World" "CMake" REGEX_REPLACED_STRING "Hello, World!")
message(STATUS "${REGEX_REPLACED_STRING}")  # 输出:Hello, CMake!

# 使用正则表达式匹配字符串中的所有匹配项
string(REGEX MATCHALL "l+" MATCHALL_VAR "Hello, World!")
list(JOIN MATCHALL_VAR ", " MATCHALL_JOINED)
message(STATUS "Matches: ${MATCHALL_JOINED}")  # 输出:Matches: ll, l

# 连接多个字符串并将结果存储在一个变量中
string(CONCAT RESULT "Hello" ", " "World!")
message(STATUS "${RESULT}")  # 输出:Hello, World!

# 比较两个字符串
string(COMPARE EQUAL "Hello" "Hello" IS_EQUAL)
if(IS_EQUAL)
  message(STATUS "Strings are equal")
endif()

(12)生成器表达式

生成器表达式在构建时求值,用于条件编译、链接等。

target_compile_definitions(MyProject PRIVATE $<$<CONFIG:Debug>:DEBUG_BUILD>)

(13) 模块和包

CMake 支持模块化,可以通过 include 命令包含其他 CMake 文件。

include(MyModule)

(14) List操作

在 CMake 中,list() 命令用于处理列表。列表是一种包含多个元素的数据结构,元素之间用分号(;)分隔。list() 命令提供了许多子命令来操作列表,如添加、删除、查找、排序等。

cmake_minimum_required(VERSION 3.10)
project(ListProcessingExample)

# 定义一个列表
set(MY_LIST "A" "B" "C" "A" "D" "B")

# 移除重复项
list(REMOVE_DUPLICATES MY_LIST)
message(STATUS "After removing duplicates: ${MY_LIST}")  # 输出:A;B;C;D

# 插入新项
list(INSERT MY_LIST 2 "E")
message(STATUS "After inserting 'E': ${MY_LIST}")  # 输出:A;B;E;C;D

# 获取列表长度
list(LENGTH MY_LIST LENGTH_VAR)
message(STATUS "Length: ${LENGTH_VAR}")  # 输出:Length: 5

# 获取指定位置的项
list(GET MY_LIST 3 ITEM)
message(STATUS "Item at index 3: ${ITEM}")  # 输出:Item at index 3: C

# 查找项的位置
list(FIND MY_LIST "D" INDEX)
message(STATUS "Index of 'D': ${INDEX}")  # 输出:Index of 'D': 4

# 排序列表
list(SORT MY_LIST)
message(STATUS "Sorted list: ${MY_LIST}")  # 输出:A;B;C;D;E

# 反转列表
list(REVERSE MY_LIST)
message(STATUS "Reversed list: ${MY_LIST}")  # 输出:E;D;C;B;A

# 获取子列表
list(SUBLIST MY_LIST 1 3 SUB_LIST)
message(STATUS "Sublist: ${SUB_LIST}")  # 输出:D;C;B

# 将列表连接成字符串
list(JOIN MY_LIST "-" JOINED_STRING)
message(STATUS "Joined string: ${JOINED_STRING}")  # 输出:E-D-C-B-A
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值