CMake 常用命令详解:从版本声明到安装部署

目录

  • [1. cmake_minimum_required 函数](#1. cmake_minimum_required 函数)
  • [2. project 函数](#2. project 函数)
  • [3. include 函数](#3. include 函数)
  • [4. install 函数](#4. install 函数)
  • [5. add_executable 函数](#5. add_executable 函数)
  • [6. 小结与经典面试题](#6. 小结与经典面试题)
    • [6.1 本文小结](#6.1 本文小结)
    • [6.2 经典面试题](#6.2 经典面试题)

1. cmake_minimum_required 函数

📚函数作用:指定项目所需要的最低CMake版本,放在顶级CMakeLists.txt的第一行。

基本形式

bash 复制代码
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])

参数解释

参数 含义
VERSION 关键字,表示后面跟的是版本号
<min> 版本号,<major>[.<minor>[.<patch>[.<tweak>]]] 形式,指定所需的最低 CMake 版本(如 3.18)
[...<policy_max>] 可选,指定策略兼容的最高版本,用于限定策略行为的上限
FATAL_ERROR 可选,若指定,当 CMake 版本不满足时会终止配置并报错(CMake 2.6+ 默认为此行为)

2. project函数

📚 函数作用:指定项⽬名字,放在顶级CMakeLists⽂件的第⼆⾏,⼦⽬录中⼀般⽆需调⽤。

基本形式

bash 复制代码
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
		[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
		[DESCRIPTION <project-description-string>]
		[HOMEPAGE_URL <url-string>]
		[LANGUAGES <language-name>...])

关键参数

参数 含义
<PROJECT-NAME> 项目名称(如 MyProject),用于生成默认变量(如 PROJECT_NAME)
VERSION(可选) 项目版本号(如 1.0.0),会自动定义 PROJECT_VERSION 等变量
DESCRIPTION(可选) 项目描述信息(用于生成文档或包配置)
HOMEPAGE_URL(可选) 项目主页 URL
LANGUAGES(可选) 指定项目支持的语言(如 C、CXX、Fortran、ASM 等)

project() 执⾏之后,CMake 会⾃动创建以下变量,可在后续命令中使⽤:

变量 描述
PROJECT_NAME 项⽬名称(如 MyProject)
CMAKE_PROJECT_NAME 顶级项⽬名称(与 PROJECT_NAME 相同)
PROJECT_VERSION 完整版本号(如 1.2.3)
PROJECT_VERSION_MAJOR 主版本号(如 1)
PROJECT_VERSION_MINOR 次版本号(如 2)
PROJECT_VERSION_PATCH 修订号(如 3)
PROJECT_SOURCE_DIR 顶级 CMakeLists.txt 所在⽬录(即源⽂件树根⽬录)
PROJECT_BINARY_DIR 构建⽬录(如 build/)

📌注意:

1 ⼤多数项⽬都只有⼀个名字,复杂项⽬如c++的boost 库,每⼀个⼦功能都设置⼀个project。

2 项⽬的顶级 CMakeLists.txt ⽂件必须包含对 project() 命令的直接调⽤。

PROJECT_NAME 变量的使⽤场景:

1 动态库的输出名称

2 cmake配置⽂件的名称

3 命名空间的名称

PROJECT_VERSION 变量的使⽤场景:

1 打印变量

2 ⽣成pkg-config或者.cmake对应的版本配置⽂件

3 动态库/静态库的的版本号

举例如下:

bash 复制代码
cmake_minimum_required(VERSION 3.18)
project(hello VERSION 1.2.3 LANGUAGES CXX)
add_executable(hello src/main.cpp)

message(STATUS "PROJECT_NAME: ${PROJECT_NAME}")
message(STATUS "PROJECT_VERSION: ${PROJECT_VERSION}")
message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
message(STATUS "PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
message(STATUS "CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")

执行命令cmake ../即可得到如下输出结果

bash 复制代码
-- PROJECT_NAME: hello
-- PROJECT_VERSION: 1.2.3
-- PROJECT_SOURCE_DIR: /Users/lj/Desktop/CMakeDemo/hello
-- PROJECT_BINARY_DIR: /Users/lj/Desktop/CMakeDemo/hello/build
-- CMAKE_CURRENT_LIST_FILE: /Users/lj/Desktop/CMakeDemo/hello/CMakeLists.txt
-- CMAKE_CURRENT_LIST_DIR: /Users/lj/Desktop/CMakeDemo/hello

3.include函数

📚 函数作用:加载指定的脚本⽂件或者功能模块到当前CMakeLists上下⽂中并运⾏。

基本形式

bash 复制代码
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>] [NO_POLICY_SCOPE])

<file|module> :表示要运行的文件或者模块名.

CMake进⼊⼦⽬录之后,内置变量的变化情况如下表所示:

变量名 进⼊⼦⽬录后是否变化? 说明
CMAKE_CURRENT_SOURCE_DIR ❌ 不变化 还是⽗⽬录的源代码树的⽬录
CMAKE_CURRENT_BINARY_DIR ❌ 不变化 还是⽗⽬录的构建树的⽬录
CMAKE_CURRENT_LIST_FILE ✅ 变化 变为⼦⽬录的 CMakeLists.txt ⽂件全路径
CMAKE_CURRENT_LIST_DIR ✅ 变化 变为⼦⽬录的 CMakeLists.txt ⽂件⽬录

📌 说明:

CMAKE_CURRENT_SOURCE_DIR 与 CMAKE_CURRENT_BINARY_DIR 在add_subdirectory() 进入子目录后,会切换为子目录对应的源码目录与构建目录;而CMAKE_CURRENT_LIST_FILE 与 CMAKE_CURRENT_LIST_DIR 始终指向当前正在被解析的 CMakeLists.txt 文件及其所在目录,因此会随进入子目录而变化。化情况

举例理解:

此处我们创建一个新工程项目然后打印对应的变量辅助理解:

目录结构

bash 复制代码
test_include
├── CMakeLists.txt
├── build
└── sub
	└── sub.cmake

新建⽂件-CMakeLists.txt

bash 复制代码
# 顶层CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(TestInclude)

message(STATUS "CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")

include(sub/sub.cmake)

新建⽂件-sub.cmake

bash 复制代码
message(STATUS "from sub/sub.cmake")
message(STATUS "CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")

运⾏cmake

bash 复制代码
[lijing@localhost build]$ cmake ../
-- from top-level CMakeLists.txt
-- CMAKE_CURRENT_SOURCE_DIR: /home/lijing/testInclude
-- CMAKE_CURRENT_LIST_FILE: /home/lijing/testInclude/CMakeLists.txt
-- CMAKE_CURRENT_LIST_DIR: /home/lijing/testInclude
-- from sub/sub.cmake
-- CMAKE_CURRENT_SOURCE_DIR: /home/lijing/testInclude
-- CMAKE_CURRENT_LIST_FILE: /home/lijing/testInclude/sub/sub.cmake
-- CMAKE_CURRENT_LIST_DIR: /home/lijing/testInclude/sub
-- Configuring done
-- Generating done

📌注意:

观察运行结果发现,只有CMAKE_CURRENT_LIST_FILE和CMAKE_CURRENT_LIST_DIR 才能定位正在执⾏的cmake⽂件路径和所属的目录,不论是include 还是add_subdirectory命令。

4.install函数

📚 函数作用:安装(简单理解为cp) 将 ⼆进制,静态库,动态库,头⽂件,配置⽂件 部署到指定⽬录。

bash 复制代码
install(TARGETS <targets>... [EXPORT <export-name>]
		[RUNTIME DESTINATION <dir>]
		[LIBRARY DESTINATION <dir>]
		[ARCHIVE DESTINATION <dir>]
		[INCLUDES DESTINATION <dir>]
		[...])
install(FILES <files>... DESTINATION <dir>
		[PERMISSIONS <permissions>...]
		[CONFIGURATIONS <configs>...]
		[COMPONENT <component>]
		[...])
install(DIRECTORY <dirs>... DESTINATION <dir>
		[FILE_PERMISSIONS <permissions>...]
		[DIRECTORY_PERMISSIONS <permissions>...]
		[...])
install(EXPORT <export-name> DESTINATION <dir>
		[NAMESPACE <namespace>::]
		[FILE <filename>]
		[...])

关键参数:

参数 含义
TARGETS 安装使用 add_executable() 和 add_library() 构建的目标文件
FILES 安装文件
DIRECTORY 安装整个目录
EXPORT 安装导出目录,用于发布自己的程序,供别人使用
DESTINATION 指定安装路径,路径可以是绝对路径,也可以是相对路径(相对于 CMAKE_INSTALL_PREFIX)

🐳 CMAKE_INSTALL_PREFIX的 默认路径为 /usr/local,此处特指Linux环境下。

5.add_executable函数

📚 函数作用:指示cmake从源代码生成一个一个可执行文件.

基本形式

bash 复制代码
add_executable(生成的可执行文件名字 [WIN32] [MACOSX_BUNDLE]
				[EXCLUDE_FROM_ALL]
				依赖的源文件)

关键参数

参数 含义
target_name 可执行文件的名称(不包含扩展名,如 myapp),项目内部唯一
<sources> 源文件列表(如 src/main.cpp)

📌 注意

默认情况下,生成的二进制可执行文件会放到构建目录树上,即源外构建的build目录下。当然也可> 以使用属性RUNTIME_OUTPUT_DIRECTORY修改默认的存放位置。

6. 小结与经典面试题

6.1 本文小结

本文围绕 CMake 中最常用的五个命令展开,梳理了它们的作用、基本形式与关键参数:

  • cmake_minimum_required():声明项目所需的最低 CMake 版本,必须放在顶级 CMakeLists.txt 的第一行,是配置阶段的"版本守门员"。
  • project():定义项目名称、版本、描述与支持语言,并自动生成 PROJECT_NAME、PROJECT_VERSION、PROJECT_SOURCE_DIR 等一系列变量,是后续逻辑的基础。
  • include():把外部脚本或模块加载进当前上下文执行,同时要注意 CMAKE_CURRENT_SOURCE_DIR、CMAKE_CURRENT_LIST_FILE 等内置变量在进入子目录后的变化规律。
  • install():把可执行文件、库、头文件、目录等"拷贝"到安装目录,DESTINATION 相对路径以 CMAKE_INSTALL_PREFIX(Linux 默认 /usr/local)为基准。
  • add_executable():由源文件生成可执行目标,默认输出到构建目录,可通过 RUNTIME_OUTPUT_DIRECTORY 调整输出位置。

一句话概括:版本声明 → 项目定义 → 脚本复用 → 目标构建 → 安装部署,这五步基本覆盖了一个 CMake 工程的骨架。

6.2 经典面试题

Q1:cmake_minimum_required() 为什么必须写在第一行?它和 cmake_policy() 有什么关系?

答:它必须在任何可能受策略影响的命令之前执行,因为该命令会设置 CMake 的策略版本(Policy Version) 。CMake 的每条策略都有 OLD 和 NEW 两种行为,cmake_minimum_required(VERSION x.y) 会把所有在该版本之前引入的策略自动设为 NEW,从而保证不同 CMake 版本下行为一致。若写在后面,前面的命令可能已按旧策略执行,导致行为不可预期。需要精细控制时,可再用 cmake_policy(SET CMP00xx NEW) 单独设置。

Q2:project() 会自动生成哪些常用变量?PROJECT_SOURCE_DIR 和 CMAKE_SOURCE_DIR 有什么区别?

答:project() 会生成 PROJECT_NAME、PROJECT_VERSION(及 _MAJOR/_MINOR/_PATCH)、PROJECT_SOURCE_DIR、PROJECT_BINARY_DIR、PROJECT_LANGUAGES 等变量。

区别在于作用域:

  • CMAKE_SOURCE_DIR / CMAKE_BINARY_DIR 始终指向顶级工程的源码目录与构建目录,全局唯一;
  • PROJECT_SOURCE_DIR / PROJECT_BINARY_DIR 指向最近一次 project() 调用 所在目录。在子目录中再次调用 project() 后,它们会变为子项目的目录。

Q3:include() 和 add_subdirectory() 有什么区别?

答:两者都能复用 CMake 脚本,但语义不同:

对比项 include() add_subdirectory()
处理对象 一个 .cmake 脚本或模块 一个包含 CMakeLists.txt 的子目录
作用域 在当前作用域内直接执行,变量、目标共享 创建新的目录作用域,变量默认不向父级回传
构建系统 不产生新的构建单元 会生成子目录对应的构建规则
典型用途 引入函数、宏、工具脚本 组织多模块工程

另外,include() 后 CMAKE_CURRENT_LIST_FILE / CMAKE_CURRENT_LIST_DIR 会变为被包含脚本的路径,而 CMAKE_CURRENT_SOURCE_DIR 保持不变。

Q4:install() 中 DESTINATION 写相对路径和绝对路径有什么区别?CMAKE_INSTALL_PREFIX 起什么作用?

答:DESTINATION 写相对路径时,最终安装位置为 ${CMAKE_INSTALL_PREFIX}/<相对路径>,这是推荐做法,便于用户通过 -DCMAKE_INSTALL_PREFIX=... 或 cmake --install . --prefix ... 自定义安装位置;写绝对路径则完全忽略 CMAKE_INSTALL_PREFIX,可移植性差,一般只在特殊场景使用。Linux 下 CMAKE_INSTALL_PREFIX 默认为 /usr/local,Windows 下通常为 C:/Program Files/<项目名>。

Q5:add_executable() 生成的可执行文件默认输出到哪里?如何修改?

答:默认输出到当前构建目录(即 CMAKE_CURRENT_BINARY_DIR),也就是源外构建时 build/ 下对应位置。修改方式有两种:

cmake 复制代码
# 方式一:设置目标属性
set_target_properties(myapp PROPERTIES
    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 方式二:设置全局变量(需在 add_executable 之前)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_executable(myapp src/main.cpp)

注意多配置生成器(如 Visual Studio)下还会追加 Debug/、Release/ 子目录,可用 RUNTIME_OUTPUT_DIRECTORY_DEBUG 等按配置单独指定。

Q6:一个标准的最小 CMakeLists.txt 应该包含哪些内容?

答:

cmake 复制代码
cmake_minimum_required(VERSION 3.18)   # 1. 声明最低版本
project(MyApp VERSION 1.0.0 LANGUAGES CXX)  # 2. 定义项目
add_executable(myapp src/main.cpp)     # 3. 生成可执行目标
install(TARGETS myapp RUNTIME DESTINATION bin)  # 4. 安装规则

这四行构成了一个可配置、可构建、可安装的最小工程骨架,其余内容(依赖查找、编译选项、测试等)都在此基础上扩展。

相关推荐
D e re k ZH4 小时前
P5025 [SNOI2017] 炸弹
c++·算法
wuminyu4 小时前
Java字节码学习总结:字节码如何加载、解析和执行
java·linux·c语言·jvm·c++
qq_406981034 小时前
c++的decltype是什么
开发语言·c++
坤坤子吖4 小时前
算法学习——单调队列
开发语言·c++·笔记·学习·算法
杜 硕5 小时前
从零开始的C++生活——第六讲——01
开发语言·c++·生活
Risehuxyc7 小时前
C++(VS2026)使用Ncap库的配置
c++
香蕉大香蕉(06敬畏市场)8 小时前
MySQL 单点详解(03)
java·数据库·mysql·面试·八股·大厂实习
4ever.ov08 小时前
精学C++第一站 从命名空间到引用:C++入门核心语法全梳理(13000字长文)
开发语言·c++·clion
听风若依8 小时前
C++模板初阶
c++·算法