当前位置: 首页 > news >正文

cmake学习day01

基本起点

本笔记的主要参考文献是cmake文档,对文档的二次提炼和补充学习。

1. cmake_minimum_required()

任何项目的最顶层CMakeLists.txt都必须首先使用 cmake_minimum_required() 命令指定最低 CMake 版本。这建立策略设置并确保以下 CMake 函数以兼容的 CMake 版本运行。
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
要求 CMake 的最低版本,确保运行的 CMake 版本不低于该版本,否则会停止处理项目并报告错误。

  • <min>:必需的,指定项目的 CMake 最低版本,格式为 major.minor[.patch[.tweak]],例如 3.12、3.12.1 等。
    • major 是主版本号。
    • minor 是次版本号。
    • patch 是补丁版本号(可选)。
    • tweak 是修订版本号(可选)。
  • [...<policy_max>]:可选的,从 CMake 3.12 开始支持,用于指定策略版本的上限,格式同 <min>。如果指定,必须至少为<min>版本。在旧版本 CMake 中会被忽略。
  • [FATAL_ERROR]:可选的,CMake 2.6 及更高版本接受但忽略该选项。在 CMake 2.4 及更低版本中,若指定此选项,当运行的 CMake 版本低于 <min> 时会报错,而不是仅发出警告。

示例

cmake_minimum_required(VERSION 3.31)

2. add_executable()

使用指定的源文件向项目添加可执行文件。分为三类:普通可执行文件,普通可执行文件,别名可执行文件。

普通可执行文件

add_executable(<name> <options>... <sources>...)
add_executable(可执行文件名 源文件1 源文件2 ...)

添加一个名为<name>的 可执行 目标,该目标将从命令调用中列出的源文件构建。

  • WIN32
    自动设置 WIN32_EXECUTABLE 目标属性。 在 Windows 上构建一个带有 WinMain 入口点的可执行文件。当此属性设置为 true 时,在 Windows 上链接的可执行文件将使用 WinMain() 入口点而不是 main() 创建。 这使其成为 GUI 可执行文件而不是控制台应用程序。简单说 Windows 平台上生成“窗口程序”而非控制台程序(即不会弹出命令行黑框)。
  • MACOSX_BUNDLE
    自动设置 MACOSX_BUNDLE 目标属性。 (在 macOS 或 iOS 上将可执行文件构建为应用程序包,本次学习忽略)。
  • EXCLUDE_FROM_ALL
    自动设置 EXCLUDE_FROM_ALL 目标属性。 将此目标属性设置为 true(或 false)值,以将目标从包含目录及其祖先目录的“all”目标中排除(或包含)。如果排除,例如在包含目录或其祖先目录中运行 make 将默认不会构建该目标。简而言之就是排除目标项。
  • <name> 对应于逻辑目标名称,并且在项目中必须是全局唯一的。
  • CMake 默认会把构建的可执行程序放在 cmake-build-debug 目录中。

导入的可执行文件

add_executable(<name> IMPORTED [GLOBAL])
参数含义
<name>你给这个外部可执行文件起的内部名字(目标名)
IMPORTED说明这个目标是“外部导入的”,不由当前项目编译生成
GLOBAL(可选)使该目标在所有子目录中都可见
  • 使用场景:你已经有 .exe / .out 可执行文件,希望在构建流程中用它。

别名可执行文件

add_executable(<name> ALIAS <target>)

CMake 中的 目标别名(alias target)功能,虽然不像 IMPORTED 那样常见,但在模块化和大型项目中非常有用。假设你有个库或者程序,它的目标名很长、或者跟目录强绑定、或者不方便跨目录引用,CMake 提供 ALIAS 语法让你起个简单名字、跨模块引用。
示例:

add_executable(myproject_internal_app app.cpp)
# 给这个内部目标起个别名
add_executable(MyApp ALIAS myproject_internal_app)
  • 使用 ALIAS 的条件
    • 只能为已经定义好的目标起别名:所以你不能先写 add_executable(MyApp ALIAS something),必须something已经存在。
    • ALIAS 是只读的:你不能修改别名目标的属性。
    • ALIAS 主要用于公共接口:尤其是在 add_subdirectory()、install(EXPORT)、模块封装中,用于隐藏实现细节,导出简洁的接口。

3.project()

设置项目名称。

project(<PROJECT-NAME> [<language-name>...])
参数含义
<PROJECT-NAME>项目的名字
<language-name>项目使用的编程语言,如 C, CXX, Fortran
示例:
project(MyApp CXX)
  • 项目名叫 MyApp
  • 使用 C++ 编译器(CXX)
  • CMake 会自动启用 C++ 支持,并检查环境是否具备对应编译器
project(<PROJECT-NAME>[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]][DESCRIPTION <project-description-string>][HOMEPAGE_URL <url-string>][LANGUAGES <language-name>...])
关键词说明
VERSION项目的版本号,支持最多四段(如 1.2.3.4
DESCRIPTION项目的简介说明
HOMEPAGE_URL项目的主页地址(可以是 GitHub 链接等)
LANGUAGES显式设置支持的语言,如 C CXX,可省略(自动推断)
  • 可以指定多个语言支持
project(MyProject LANGUAGES C CXX)

4.基本起点包含函数各种情况练习

练习 1:最基础的情况

项目结构

Cmake_learn/
├── CMakeLists.txt
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.31)
project(Cmake_learn)
set(CMAKE_CXX_STANDARD 17)
add_executable(Cmake_learn main.cpp)

main.cpp

#include <iostream>
int main() {auto lang = "C++";std::cout << "Hello and welcome to " << lang << "!\n";for (int i = 1; i <= 5; i++) {std::cout << "i = " << i << std::endl;}return 0;}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

练习 2:指定项目版本号与描述

cmake_minimum_required(VESSION 3.31)
project(Cmake_learn CXX) #设定项目名称和语言
set(CMAKE_CXX_STANDARD 17) #设置C++标准为C++17
add_executable(Cmake_learn main.cpp) #添加可执行文件,指定源文件

main.cpp文件同练习1。

练习 3:添加多个源文件的可执行目标

//main.cpp
#include <iostream>
#include "add.h"
int main() {std::cout << "Add: " << add(2, 3) << "\n";return 0;
}
//add.cpp
#include "add.h"
int add(int a, int b) { return a + b; }
//add.h
int add(int a, int b);
#倘若main.cpp、 add.cpp、add.h在同一目录下
#CMakeList.txt
cmake_minimum_required(VERSION 3.31)
project(Cmake_learn)
set(CMAKE_CXX_STANDARD 17)
add_executable(MathApp main.cpp add.cpp)#为规范代码习惯,最好将头文件和源文件分开存放。#CMakeList.txt
cmake_minimum_required(VERSION 3.31)
project(Cmake_learn)
set(CMAKE_CXX_STANDARD 17) #设置C++标准为C++17
add_executable(Cmake_learn src/main.cpp src/add.cpp) #添加可执行文件,指定源文件x
target_include_directories(Cmake_learnPRIVATE ${CMAKE_SOURCE_DIR}/include
)

target_include_directories后面详细学习介绍,这里先记住大概格式。

练习 4:使用 IMPORTED 声明外部工具

cmake_minimum_required(VERSION 3.14)
project(CodeGenDemo)# 声明已存在的外部可执行程序
add_executable(CodeGen IMPORTED GLOBAL)
set_target_properties(CodeGen PROPERTIESIMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/tools/CodeGen.exe"
)# 假设 CodeGen.exe 生成一个 cpp 文件
add_custom_command(OUTPUT generated.cppCOMMAND CodeGenCOMMENT "Generating source code..."
)add_executable(MainApp generated.cpp)
add_dependencies(MainApp CodeGen)

练习 5:使用 ALIAS 简化内部目标命名

cmake_minimum_required(VERSION 3.10)project(CoreAliasDemo)# 真正的可执行程序
add_executable(core_exe main.cpp)# 给它起一个别名
add_executable(CoreRunner ALIAS core_exe)# 可以用别名参与链接、依赖等
add_custom_command(TARGET CoreRunnerPOST_BUILDCOMMAND CoreRunnerCOMMENT "Running CoreRunner post-build step"
)

5.configure_file()

configure_file(<input> <output> [@ONLY] [NEWLINE_STYLE [UNIX|DOS|WIN32]])

将一个模板文件(输入)拷贝为一个输出文件,并在其中替换 ${}@VAR@ 形式的变量。
没学会,项目不太用得上,暂时搁置后面补。

6.使用 file(GLOB) 动态获取文件

file(GLOB SOURCES "src/*.cpp")  # 匹配 src 目录下所有 .cpp 文件
add_executable(Cmake_learn ${SOURCES})

优点:无需手动维护文件列表。
缺点:如果 src 目录下没有 .cpp 文件,仍会报错。
若文件嵌套在多级目录中,可使用递归匹配:

file(GLOB_RECURSE SOURCES "src/**/*.cpp")  # 匹配 src 及子目录中所有 .cpp 文件
  • GLOB:只在当前目录及其指定的子目录中搜索文件,不会递归地搜索所有子目录。例如,file(GLOB files "src/*.cpp") 会搜索 src 目录下所有扩展名为 .cpp 的文件,但不会搜索 src 目录的子目录。
  • GLOB_RECURSE:会递归地搜索当前目录及其所有子目录,包括多级嵌套的子目录。例如,file(GLOB_RECURSE files "src/*.cpp") 会搜索 src 目录及其所有子目录下所有扩展名为 .cpp 的文件。
  • GLOB:适用于项目结构简单、文件分布较集中且不需要递归搜索的场景。
  • GLOB_RECURSE:适用于项目结构复杂、文件分布在多个子目录中,需要全面搜索的场景。

7.target_include_directories

向目标添加包含目录。用于为某个 目标(target) 添加头文件搜索路径,让编译器在编译该目标时知道去哪里找 .h 或 .hpp 文件。

target_include_directories(<target>[SYSTEM] [AFTER|BEFORE]<INTERFACE|PUBLIC|PRIVATE> [items...]
)
参数说明
<target>你要设置的目标,比如 MyAppMyLibrary
INTERFACE只对依赖该 target 的目标生效(自己不需要)
PUBLIC自己和依赖者都需要这个头文件路径
PRIVATE仅自己需要这个头文件路径
SYSTEM表示这是系统头文件路径,编译器不会警告其中的内容
AFTER / BEFORE控制添加顺序(极少使用)

练习示例

//hello.h
#ifndef HELLO_H
#define HELLO_H
void say_hello();
#endif //HELLO_H
//hello.cpp
#include <iostream>
#include "hello.h"void say_hello() {std::cout << "Hello from say_hello()!" << std::endl;
}
//main.cpp
#include "hello.h"int main() {say_hello();return 0;
}

CMakeList.txt

cmake_minimum_required(VERSION 3.10)
project(CodeGenDemo LANGUAGES CXX)# 创建可执行程序
add_executable(CodeGenDemosrc/main.cppsrc/hello.cpp
)# 添加头文件搜索路径
target_include_directories(CodeGenDemoPRIVATE ${CMAKE_SOURCE_DIR}/include
)

也可以用file进阶编写cmakeLists:

cmake_minimum_required(VERSION 3.14)
project(CodeGenDemo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS"${CMAKE_SOURCE_DIR}/src/*.cpp""${CMAKE_SOURCE_DIR}/include/*.h"
)
add_executable(CodeGenDemo ${SOURCES})
target_include_directories(CodeGenDemo PRIVATE ${CMAKE_SOURCE_DIR}/include)
  • GLOB_RECURSE:会递归地搜索当前目录及其所有子目录,包括多级嵌套的子目录。
  • CONFIGURE_DEPENDS:如果文件系统发生了变化(新增或删除了文件),下次重新 cmake 配置时自动重新扫描这个 GLOB。没有这个选项的话,哪怕你新加了 .cpp 文件,CMake 也不会知道,除非你手动删掉 build/ 目录重新配置。
字符串含义
${CMAKE_SOURCE_DIR}当前项目的根目录(CMakeLists.txt 所在)
/src/*.cpp查找 src/ 目录下以及其子目录中所有 .cpp 文件
/include/*.h查找 include/ 目录下以及其子目录中所有 .h 文件

在这里插入图片描述

http://www.xdnf.cn/news/697123.html

相关文章:

  • [CARLA系列--03]如何打包生成CARLA 0.9.15的非编辑版(地图的加载与卸载)
  • NW845NW850美光闪存颗粒NW883NW889
  • 把数据库做得能扩展:Aurora DSQL 的故事
  • AxumStatusCode细化Rust Web标准格式响应
  • 配置vscode中java.configuration.runtimes
  • Java设计模式之命令模式详解
  • XJTU-SY轴承振动数据集的json自封装
  • 深度学习论文: FastVLM: Efficient Vision Encoding for Vision Language Models
  • Test-Time Zero-Shot Temporal Action Localization
  • 操作系统导论 第38章:廉价冗余磁盘阵列(RAID)
  • 【C/C++】delete nullptr;
  • android系统framework的几个新面试题目(涉及binder,input,SurfaceFlinger带答案)
  • Tomcat运行比较卡顿进行参数调优
  • 案例解读 | 某外资在华汽车系统企业综合运维平台建设实践
  • Java消息队列应用:Kafka、RabbitMQ选择与优化
  • java读取excel数据中字段是否为金额格式
  • vue或者前端适配makedown推荐开源依赖
  • dart常用语法详解/数组list/map数据/class类详解
  • golang 柯里化(Currying)
  • 720全景展示:VR全景的技术原理及应用
  • Python进阶【一】 :线程、进程与协程
  • Vite Vue3 配置 Composition API 自动导入与项目插件拆分
  • 输配电行业国产PLM转型方案:南通禛华电气的云PLM研发转型
  • rsync 如何通过参数加上端口号
  • 大观杂志大观杂志社大观编辑部2025年第4期目录
  • Java 并发编程通关秘籍:多线程基础 + 锁机制 + 工具类 + 性能优化
  • Appium+python自动化(七)- 认识Appium- 上
  • 【AI算法工程师面试指北】大模型微调中的灾难性遗忘该如何避免?
  • 多台电脑共用一个ip地址可以吗?会怎么样
  • Screen 连接远程服务器(Ubuntu)