【cmake】定义函数

CMake函数定义、调用与返回值传递详解
本文介绍了在CMake中如何定义函数,包括函数名、形参的使用,以及如何通过形参传递返回值。还讲解了如何在不同文件间引入包含函数定义的文件进行调用。

1、定义函数

cmake 中定义函数的格式如下,function 的第一个参数是函数名,随后跟着的都是函数形参名

function(function_name param1 param2 ...)
    
endfunction()

假设现在要定义一个名为 greet 的函数,有两个形参,分别为 name 、age

function(greet name age)
    message(STATUS "hello, I'm ${name}, ${age} years old")
endfunction()

调用函数的方法和C语言一样,不同参数之间使用空格隔开

set(NAME "Jack")
greet(${NAME} 14)

2、传递函数返回值

一般来说,cmake 中的函数更多还是用于执行逻辑,并不用于传递返回值,若要传递返回值,则需要通过形参来传递返回值,类似于C语言中通过函数形参传递返回值。

稍微修改上述的例子,函数的最后一个形参 output 用于传递函数返回值,关键在于 PARENT_SCOPE,相当于让该变量的作用域和父级一样。

function(greet name age output)
    message(STATUS "hello, I'm ${name}, ${age} years old")
    # 关键是这里的 PARENT_SCOPE
<think>我们正在讨论CMake函数的返回值机制。请注意,CMake函数没有传统编程语言中的显式返回值(return value),而是通过以下两种方式实现类似功能: 1. **设置变量(Set Variable)**:在函数内部通过`set(... PARENT_SCOPE)`将结果赋值给父作用域的变量。 2. **输出参数(Output Parameter)**:将变量名作为参数传入,在函数内修改其值。 ### 关键机制说明 #### 1. 通过父作用域变量传递"返回值" - **原理**:在函数内部使用`set(var value PARENT_SCOPE)`将值传递到父作用域[^1]。 - **示例**: ```cmake function(get_platform result_var) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(${result_var} "linux" PARENT_SCOPE) # 修改父作用域的变量 else() set(${result_var} "unknown" PARENT_SCOPE) endif() endfunction() # 调用函数并获取结果 get_platform(MY_PLATFORM) message("Platform: ${MY_PLATFORM}") # 输出: Platform: linux (在Linux系统上) ``` **注意**:`${result_var}`在函数内被解引用为`MY_PLATFORM`,因此实际设置的是父作用域的`MY_PLATFORM`变量。 #### 2. 通过参数列表返回值 - **原理**:直接修改传入的变量(需配合`PARENT_SCOPE`)。 - **对比**:与方式1本质相同,但变量名通过参数位置而非函数内硬编码指定。 #### 3. 返回值限制 - **不支持直接返回**:无法使用`return(value)`语法。 - **作用域隔离**:函数内部定义的普通变量(无`PARENT_SCOPE`)在函数外不可见[^1]: ```cmake function(fail_example) set(LOCAL_VAR "secret" PARENT_SCOPE) # 错误!意外污染父作用域 endfunction() ``` ### 高级用法 #### 返回多个值 通过多个输出参数实现: ```cmake function(get_build_info arch os) set(${arch} "x86_64" PARENT_SCOPE) set(${os} "Linux" PARENT_SCOPE) endfunction() get_build_info(MY_ARCH MY_OS) message("Arch: ${MY_ARCH}, OS: ${MY_OS}") # 输出: Arch: x86_64, OS: Linux ``` #### 返回列表 使用`;`分隔的字符串模拟列表: ```cmake function(get_sources out_list) set(result "a.cpp" "b.cpp" "c.cpp") set(${out_list} ${result} PARENT_SCOPE) endfunction() get_sources(SOURCES) foreach(src ${SOURCES}) message("Source: ${src}") # 逐行输出a.cpp, b.cpp, c.cpp endforeach() ``` ### 错误处理 通过额外返回错误码变量: ```cmake function(safe_divide result errcode dividend divisor) if(divisor EQUAL 0) set(${errcode} 1 PARENT_SCOPE) # 错误标志 else() math(EXPR quotient "${dividend}/${divisor}") set(${result} ${quotient} PARENT_SCOPE) set(${errcode} 0 PARENT_SCOPE) endif() endfunction() safe_divide(QUOTIENT ERROR_CODE 10 2) if(NOT ERROR_CODE) message("Result: ${QUOTIENT}") # 输出: 5 endif() ``` ### 最佳实践 1. **明确作用域**:所有需返回的变量必须显式使用`PARENT_SCOPE`。 2. **避免污染**:函数内部变量名使用下划线前缀(如`_temp`)减少冲突。 3. **文档说明**:注释中声明函数的输出参数: ```cmake # get_platform(<out_var>) # 设置<out_var>为当前平台名称 ``` ### 常见错误 | **错误示例** | **原因** | **修正** | |-------------|---------|---------| | `set(result "value")` | 未传递到父作用域 | 添加`PARENT_SCOPE` | | `set(${res} "value")` | 缺少解引用符号 | 添加`${}`包裹变量名 | | 在宏中使用`PARENT_SCOPE` | 宏无独立作用域 | 改用函数或直接操作调用者作用域 | --- ### §§相关问题§§ 1. CMake函数作用域与宏作用域有何区别? 2. 如何避免CMake函数中的变量污染问题? 3. CMake的`return()`命令有什么实际用途? </think>在 CMake 中,函数没有传统编程语言中的返回值(return value)概念,而是通过以下机制实现类似功能: ### CMake 函数"返回值"的核心机制 1. **变量作用域传递** 函数内部通过 `set(变量名 值 PARENT_SCOPE)` 将结果传递到父作用域: ```cmake function(get_platform result_var) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(${result_var} "linux" PARENT_SCOPE) # 关键操作 else() set(${result_var} "unknown" PARENT_SCOPE) endif() endfunction() # 调用函数 get_platform(MY_PLATFORM) message("Platform: ${MY_PLATFORM}") # 输出: linux (在Linux系统) ``` 这里 `${result_var}` 被解引用为 `MY_PLATFORM`,通过 `PARENT_SCOPE` 修改父作用域变量[^1]。 2. **输出参数模式** 将变量名作为参数传入函数: ```cmake function(calculate_sum a b out_var) math(EXPR result "${a} + ${b}") set(${out_var} ${result} PARENT_SCOPE) endfunction() calculate_sum(3 5 SUM_RESULT) message("3+5=${SUM_RESULT}") # 输出: 3+5=8 ``` ### 关键技术细节 1. **返回值限制** - 不支持直接 `return(value)` 语法 - 无法返回复杂数据结构(如列表需用 `;` 分隔的字符串模拟) - 函数内局部变量不会自动传出 2. **多返回值实现** ```cmake function(get_sysinfo arch_var os_var) set(${arch_var} ${CMAKE_HOST_SYSTEM_PROCESSOR} PARENT_SCOPE) set(${os_var} ${CMAKE_HOST_SYSTEM_NAME} PARENT_SCOPE) endfunction() get_sysinfo(MY_ARCH MY_OS) message("Arch: ${MY_ARCH}, OS: ${MY_OS}") ``` 3. **返回列表的方法** ```cmake function(get_source_files out_list) set(result "main.cpp;utils.cpp;lib.cpp") set(${out_list} ${result} PARENT_SCOPE) endfunction() get_source_files(SOURCES) add_executable(app ${SOURCES}) ``` ### 错误处理模式 通过额外的状态变量返回错误码: ```cmake function(safe_divide dividend divisor result errcode) if(divisor EQUAL 0) set(${errcode} 1 PARENT_SCOPE) # 错误码 else() math(EXPR quotient "${dividend}/${divisor}") set(${result} ${quotient} PARENT_SCOPE) set(${errcode} 0 PARENT_SCOPE) endif() endfunction() safe_divide(10 2 QUOTIENT ERROR_CODE) if(NOT ERROR_CODE) message("Result: ${QUOTIENT}") # 输出: 5 endif() ``` ### 最佳实践 1. **命名规范** 输出参数使用 `_result` 后缀:`get_value(foo_result)` 2. **作用域隔离** 函数内局部变量添加下划线前缀:`set(_temp "value")` 3. **参数解析** 使用 `cmake_parse_arguments` 处理复杂参数(支持 CMake 3.5+): ```cmake function(my_func) set(options VERBOSE) set(oneValueArgs OUTPUT) set(multiValueArgs SOURCES) cmake_parse_arguments(MY "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(MY_VERBOSE) message("Sources: ${MY_SOURCES}") endif() set(${MY_OUTPUT} "result" PARENT_SCOPE) endfunction() ``` 4. **文档说明** 在函数前添加注释说明输出参数: ```cmake # get_platform(<output_var>) # 将平台名称保存到<output_var> ``` ### 常见错误 ```cmake # 错误示例1:缺少 PARENT_SCOPE function(wrong_example) set(RESULT "value") # 仅修改函数内局部变量 endfunction() # 错误示例2:未解引用变量名 function(another_wrong out_var) set(out_var "value" PARENT_SCOPE) # 应写为 set(${out_var} ...) endfunction() ``` > 📌 **核心规则**:CMake 函数通过修改**父作用域的命名变量**来模拟返回值,必须同时使用 **`${}`解引用**和**`PARENT_SCOPE`作用域限定**[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值