CMake 033:函数与宏核心知识点整理
@
Bilibili 同步视频
一、CMake 函数与宏的核心三大本质区别
1. 参数处理机制不同
-
CMake 函数:传入参数会被解析为真正变量,支持
if、foreach等需要变量类型的语法判断、遍历操作,可直接做布尔判定、列表迭代。 -
CMake 宏:仅做纯文本原地替换,参数本质是字符串字面量,无法被识别为变量,不能直接用于
foreach(LISTS)、条件布尔判断,只能硬编码字面内容。
示例:宏中传入
TRUE只会当成普通字符串,条件判断默认判定为假;函数中ARG2=TRUE可直接进入真值分支。
2. 变量作用域完全不同
(1)宏的作用域
宏是代码文本粘贴展开,无独立作用域,宏内set修改的变量直接作用于调用者上下文,外部可以直接读写宏内部定义的变量。
(2)函数默认作用域(局部隔离)
函数自带独立局部作用域:
-
函数内部可读外部上层变量;
-
函数内直接
set(变量 值)只会创建局部同名变量,不会修改外部同名变量,函数执行结束局部变量直接销毁,外部无法访问; -
形参优先级高于外部全局同名变量:内外变量重名时,优先读取函数局部形参。
(3)跨作用域修改外部变量方案:PARENT_SCOPE
想要函数内部修改调用者上层变量,赋值时必须显式指定作用域:
set(外部变量 新值 PARENT_SCOPE)
-
PARENT_SCOPE:仅向上暴露给直接调用者层级,无法直接穿透多层父目录、全局,不是全局变量; -
多层子目录嵌套时,仅能修改直属父级变量,不会跨层级污染顶层全局,可控性更强;
-
全局变量修改范围过大,调试排错难度高,工程中优先用
PARENT_SCOPE而非全局。
3. return 关键字行为差异
-
宏禁止使用 return:宏是文本替换,
return会直接终止当前整个 CMake 脚本文件执行,而非退出宏逻辑,会导致后续构建流程中断崩溃。 -
函数支持 return:仅退出当前函数自身,不会影响外层脚本、父目录执行,用于函数内条件提前终止逻辑,是合法流程控制语法。
二、CMake 函数基础语法
1. 定义与调用规则
# 固定形参定义
function(函数名 ARG1 ARG2)
# 函数逻辑
endfunction()
# 调用:大小写不敏感,推荐小写统一风格
函数名(OFF TRUE test 1 2 3)
-
支持固定命名参数 + 变长参数:固定形参后的额外传入值,可通过
foreach遍历全部变参; -
函数定义后,全项目子目录均可直接调用(子目录定义的函数,顶层父目录能访问)。
2. 变长参数遍历特性
函数中可变参数可配合foreach(LISTS)完整迭代所有额外入参;
宏无法将参数转为列表变量,只能逐个硬编码取值,不支持批量遍历。
三、子目录场景下函数变量作用域细节
-
子目录内定义的函数:顶层父 CMakeLists.txt 可直接调用;
-
子目录函数内不带
PARENT_SCOPE的变量:仅函数局部有效,父目录完全读取不到; -
子目录函数设置
PARENT_SCOPE:仅修改当前子目录层级的父变量,不会自动同步到项目最顶层,多层嵌套需要逐层向上传递作用域; -
父子目录变量存储空间相互隔离,默认互不干扰,仅主动向上授权才会传递值。
四、工程使用总结建议
-
简单文本替换、无需变量隔离:用宏;
-
需要条件判断、循环遍历、局部变量隔离、安全返回退出:优先用函数;
-
函数需要向外回传计算结果:必须加
PARENT_SCOPE限定父级作用域,慎用全局变量避免隐性 bug; -
多子目录大型项目:依靠分层
PARENT_SCOPE做层级数据传递,保证变量作用域清晰易调试。

浙公网安备 33010602011771号