cmake函数语法

在CMake中,函数用于封装一段可重用的代码。下面是CMake函数的定义和调用的详细讲解。

定义函数

函数的定义使用function()来开始,然后指定函数名称以及任何形参列表,如下所示:

function(<function_name> [arg1 [arg2 [...]]])
   # Function code...
endfunction()

函数名称应该是唯一的,以避免与其他函数发生冲突。关键字function()endfunction()之间的代码是函数代码块。

这里的形参列表是可选的,您可以为您的函数定义零个、一个或多个参数。注意,函数调用中的参数列表是以空格分隔的,因此每个参数将自动映射到定义中的参数。

使用ARGN与ARGC

CMake中的两个特殊变量ARGNARGC对于处理函数参数尤为有用。

  • ARGN: 该变量包含函数调用时传递的所有未指定名称的参数。这在处理不确定数量的参数时很有用。
  • ARGC: 该变量包含传递给函数的参数总数。

调用函数

调用CMake函数时,只需使用函数名称并传递所需的参数。在调用函数时,在实际参数列表中定义的参数名称将被绑定到调用函数时传递的参数值。

<function_name>([arg1 [arg2 [...]]])

示例:

# 定义一个简单的函数,接收两个参数并输出它们
function(print_args ARG1 ARG2)
    message("Argument 1 is '${ARG1}'")
    message("Argument 2 is '${ARG2}'")
endfunction()

# 调用print_args函数
print_args("Hello" "World")
# 输出:
# Argument 1 is 'Hello'
# Argument 2 is 'World'

# 一个处理不确定参数量的函数示例
function(print_multiple_args)
    set(NumArgs ${ARGC})
    message("Total number of arguments: ${NumArgs}")
    foreach(Arg ${ARGN})
        message("Arg: '${Arg}'")
    endforeach()
endfunction()

# 调用print_multiple_args函数
print_multiple_args("arg1" "arg2" "arg3")
# 输出:
# Total number of arguments: 3
# Arg: 'arg1'
# Arg: 'arg2'
# Arg: 'arg3'

在电脑上实操下将有助于更好地理解CMake函数以及如何定义和调用它们。

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top

<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、付费专栏及课程。

余额充值