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

CMake进阶:解析自定义函数 / 宏的可变参数(ARGN)的指令cmake_parse_arguments

目录

1.简介

2.核心作用

3.常见使用场景

4.实战示例:自定义可执行文件函数

5.实战示例:nuttx_add_subdirectory

5.1.nuttx_add_subdirectory简介

5.2.背景:NuttX 的模块化构建体系

5.3.nuttx_add_subdirectory 的核心作用

5.4.实战示例:使用 nuttx_add_subdirectory 集成模块

5.5.关键区别:nuttx_add_subdirectory vs 标准 add_subdirectory

6.注意事项

7.总结

相关链接


1.简介

        在 CMake 中,cmake_parse_arguments 是一个用于解析自定义函数 / 宏的可变参数(ARGN 的核心命令,专门解决 “手动处理复杂参数列表繁琐且易出错” 的问题。它能自动将参数分类为开关参数(无值)、单值参数(关键字 + 1 个值)、多值参数(关键字 + 多个值),并通过前缀统一管理解析后的变量,避免全局变量污染。大大提高了 CMake 代码的可读性和可维护性。

        对于之前 “VS 工程转 CMake” 的场景(如自定义封装 add_executable、处理第三方库配置),cmake_parse_arguments 可大幅简化参数传递逻辑(例如支持自定义输出目录、依赖库、编译开关等)。

CMake实践: VS2022工程转为CMake工程过程与经验分享

cmake_parse_arguments 的语法格式固定,需指定 “参数分类规则” 和 “待解析的参数列表”:

cmake_parse_arguments(<PREFIX>          # 1. 变量前缀(解析后变量名的统一前缀,避免冲突)<OPTIONS>         # 2. 开关参数列表(仅需关键字,无值,如 "WITH_DEBUG WITH_TEST")<ONE_VALUE_ARGS>  # 3. 单值参数列表(关键字后必须跟1个值,如 "OUTPUT_DIR VERSION")<MULTI_VALUE_ARGS># 4. 多值参数列表(关键字后可跟多个值,如 "SOURCES DEPENDS")${ARGN}           # 5. 待解析的可变参数(通常是函数/宏的 ARGN 参数)
)

参数详解

参数类别作用说明示例
<PREFIX>解析后所有变量的前缀(如 MY_EXE),最终变量名格式为 PREFIX_<参数名>若前缀为 MY_EXE,开关参数 WITH_DEBUG 会生成 MY_EXE_WITH_DEBUG
<OPTIONS>开关参数(布尔型):仅需指定关键字,存在则为 TRUE,不存在为 FALSE"WITH_DEBUG WITH_TEST"
<ONE_VALUE_ARGS>单值参数:关键字后必须跟 1 个值(若未跟值,CMake 会报错)。"OUTPUT_DIR VERSION"
<MULTI_VALUE_ARGS>多值参数:关键字后可跟 多个值(值会被收集为列表)。"SOURCES DEPENDS"
${ARGN}待解析的可变参数(自定义函数 / 宏的 ARGN 变量,包含所有传入的额外参数)。函数调用时传入的 SOURCES main.cpp util.cpp 等。

示例1:基本用法

function(my_function)set(options VERBOSE FORCE)set(oneValueArgs NAME OUTPUT)set(multiValueArgs SOURCES INCLUDES)cmake_parse_arguments(MY "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})message("VERBOSE: ${MY_VERBOSE}")message("FORCE: ${MY_FORCE}")message("NAME: ${MY_NAME}")message("OUTPUT: ${MY_OUTPUT}")message("SOURCES: ${MY_SOURCES}")message("INCLUDES: ${MY_INCLUDES}")message("未解析的参数: ${MY_UNPARSED_ARGUMENTS}")
endfunction()# 调用示例
my_function(VERBOSENAME "my_project"SOURCES main.cpp util.cppINCLUDES /usr/include /opt/local/includeFORCEOUTPUT "build"EXTRA_ARG  # 这个会被识别为未解析参数
)

输出结果:

VERBOSE: TRUE
FORCE: TRUE
NAME: my_project
OUTPUT: build
SOURCES: main.cpp;util.cpp
INCLUDES: /usr/include;/opt/local/include
未解析的参数: EXTRA_ARG

示例 2:更复杂的函数

function(create_library)set(options STATIC SHARED INTERFACE)set(oneValueArgs TARGET NAME VERSION)set(multiValueArgs SOURCES DEPENDENCIES COMPILE_OPTIONS)cmake_parse_arguments(LIB"${options}""${oneValueArgs}""${multiValueArgs}"${ARGN})# 验证参数if(NOT LIB_TARGET)message(FATAL_ERROR "TARGET argument is required")endif()# 确定库类型if(LIB_STATIC)set(lib_type STATIC)elseif(LIB_SHARED)set(lib_type SHARED)elseif(LIB_INTERFACE)set(lib_type INTERFACE)else()set(lib_type STATIC)  # 默认类型endif()# 创建库if(lib_type STREQUAL "INTERFACE")add_library(${LIB_TARGET} INTERFACE)else()add_library(${LIB_TARGET} ${lib_type} ${LIB_SOURCES})endif()# 设置属性if(LIB_NAME)set_target_properties(${LIB_TARGET} PROPERTIES OUTPUT_NAME ${LIB_NAME})endif()if(LIB_DEPENDENCIES)target_link_libraries(${LIB_TARGET} PRIVATE ${LIB_DEPENDENCIES})endif()if(LIB_COMPILE_OPTIONS)target_compile_options(${LIB_TARGET} PRIVATE ${LIB_COMPILE_OPTIONS})endif()
endfunction()# 使用示例
create_library(TARGET mylibSTATICNAME "mylibrary"SOURCES src1.cpp src2.cppDEPENDENCIES Threads::Threads MathLibCOMPILE_OPTIONS -Wall -Wextra
)

示例 3:使用 PARSE_ARGV 处理复杂值

macro(complex_example)# 使用 PARSE_ARGV 版本,从第 0 个参数开始cmake_parse_arguments(PARSE_ARGV 0COMPLEX"ENABLE_A;ENABLE_B""CONFIG_FILE""FEATURES;OPTIONS")message(STATUS "ENABLE_A: ${COMPLEX_ENABLE_A}")message(STATUS "ENABLE_B: ${COMPLEX_ENABLE_B}")message(STATUS "CONFIG_FILE: ${COMPLEX_CONFIG_FILE}")message(STATUS "FEATURES: ${COMPLEX_FEATURES}")message(STATUS "OPTIONS: ${COMPLEX_OPTIONS}")
endmacro()# 调用示例
complex_example(ENABLE_ACONFIG_FILE "/path/to/config"FEATURES "feature1;feature2" "feature3"OPTIONS "option1=value1" "option2=value2"
)

2.核心作用

当你编写自定义 CMake 函数 / 宏时,若需要支持灵活的参数格式(如可选参数、多值参数),cmake_parse_arguments 能帮你:

  1. 自动区分 开关参数(如 WITH_DEBUG,仅需指定关键字,无后续值);
  2. 自动提取 单值参数(如 OUTPUT_DIR "bin",关键字后紧跟 1 个值);
  3. 自动收集 多值参数(如 SOURCES main.cpp util.cpp,关键字后紧跟多个值);
  4. 生成统一前缀的变量(如 PREFIX_WITH_DEBUGPREFIX_OUTPUT_DIR),避免变量冲突;
  5. 捕获未解析的参数(便于排查错误)。

3.常见使用场景

1.参数验证

function(validated_function)set(options "")set(oneValueArgs REQUIRED_ARG)set(multiValueArgs "")cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})# 验证必需参数if(NOT FUNC_REQUIRED_ARG)message(FATAL_ERROR "REQUIRED_ARG is required")endif()
endfunction()

2.提供默认值

function(function_with_defaults)set(options "ENABLE_FEATURE")set(oneValueArgs "TIMEOUT")set(multiValueArgs "TAGS")cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})# 设置默认值if(NOT DEFINED FUNC_TIMEOUT)set(FUNC_TIMEOUT 60)endif()if(NOT DEFINED FUNC_TAGS)set(FUNC_TAGS "default")endif()
endfunction()

3.处理互斥参数

function(exclusive_options)set(options "OPTION_A;OPTION_B")set(oneValueArgs "")set(multiValueArgs "")cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})# 检查互斥选项if(FUNC_OPTION_A AND FUNC_OPTION_B)message(FATAL_ERROR "OPTION_A and OPTION_B are mutually exclusive")endif()
endfunction()

4.实战示例:自定义可执行文件函数

以 “封装 add_executable,支持自定义输出目录、调试开关、依赖库” 为例,演示 cmake_parse_arguments 的完整用法(贴合之前的 prjXiAn 项目场景)。

1.定义自定义函数 add_my_executable

# 自定义函数:封装 add_executable,支持灵活参数
function(add_my_executable TARGET_NAME)# 步骤1:用 cmake_parse_arguments 解析参数cmake_parse_arguments(MY_EXE          # PREFIX:解析后变量的前缀(如 MY_EXE_WITH_DEBUG)"WITH_DEBUG"    # OPTIONS:开关参数(是否启用调试模式)"OUTPUT_DIR"    # ONE_VALUE_ARGS:单值参数(输出目录)"SOURCES;DEPENDS"# MULTI_VALUE_ARGS:多值参数(源文件、依赖库)${ARGN}         # 待解析的可变参数(函数调用时传入的额外参数))# 步骤2:处理解析后的参数(生成可执行文件)# 2.1 检查必填参数:SOURCES 必须存在if(NOT MY_EXE_SOURCES)message(FATAL_ERROR "add_my_executable 必须指定 SOURCES 参数(如 SOURCES main.cpp)")endif()# 2.2 创建可执行目标(核心调用 add_executable)add_executable(${TARGET_NAME} ${MY_EXE_SOURCES})# 2.3 处理输出目录(单值参数:若指定 OUTPUT_DIR,设置目标输出路径)if(MY_EXE_OUTPUT_DIR)# 用 cmake_path 处理跨平台路径(Windows 自动转 \)cmake_path(JOIN "${CMAKE_CURRENT_BINARY_DIR}" "${MY_EXE_OUTPUT_DIR}" OUTPUT_PATH)set_target_properties(${TARGET_NAME} PROPERTIESRUNTIME_OUTPUT_DIRECTORY "${OUTPUT_PATH}"  # 可执行文件输出目录)endif()# 2.4 处理调试开关(开关参数:若 WITH_DEBUG 为 TRUE,添加 DEBUG 宏)if(MY_EXE_WITH_DEBUG)target_compile_definitions(${TARGET_NAME} PRIVATE DEBUG)message(STATUS "[${TARGET_NAME}] 已启用调试模式(添加 DEBUG 宏)")endif()# 2.5 处理依赖库(多值参数:若指定 DEPENDS,链接依赖库)if(MY_EXE_DEPENDS)target_link_libraries(${TARGET_NAME} PRIVATE ${MY_EXE_DEPENDS})message(STATUS "[${TARGET_NAME}] 依赖库:${MY_EXE_DEPENDS}")endif()# 步骤3:(可选)打印未解析的参数(排查错误)if(MY_EXE_UNPARSED_ARGUMENTS)message(WARNING "[${TARGET_NAME}] 存在未解析的参数:${MY_EXE_UNPARSED_ARGUMENTS}")endif()
endfunction()

2.调用自定义函数 add_my_executable

在 CMakeLists.txt 中调用该函数,传递不同类型的参数(开关、单值、多值):

# 调用示例1:基础用法(指定源文件、输出目录)
add_my_executable(prjXiAnSOURCES src/main.cpp src/deviceManage.cpp UI/QComboBoxEx.cppOUTPUT_DIR "bin/Debug"  # 单值参数:输出目录(Windows 下自动转为 bin\Debug)
)# 调用示例2:完整用法(含调试开关、依赖库)
add_my_executable(prjXiAn_TestWITH_DEBUG              # 开关参数:启用调试模式SOURCES test/test_main.cpp test/test_device.cppOUTPUT_DIR "bin/Test"DEPENDS Qt5::Widgets ws2_32.lib  # 多值参数:依赖库(Qt Widgets + Windows 系统库)
)

3.解析结果与效果

  • 开关参数 WITH_DEBUG:调用时指定 WITH_DEBUG → MY_EXE_WITH_DEBUG = TRUE → 自动添加 DEBUG 宏。
  • 单值参数 OUTPUT_DIR:传入 OUTPUT_DIR "bin/Debug" → MY_EXE_OUTPUT_DIR = "bin/Debug" → 用 cmake_path 转为跨平台路径(Windows 下为 build\bin\Debug)。
  • 多值参数 SOURCES/DEPENDSSOURCES 传入多个 .cpp 文件 → MY_EXE_SOURCES 是包含这些文件的列表;DEPENDS 传入多个库 → MY_EXE_DEPENDS 是库列表,通过 target_link_libraries 链接。
  • 未解析参数:若误传 UNKNOWN_ARG "value" → MY_EXE_UNPARSED_ARGUMENTS = "UNKNOWN_ARG;value" → 打印警告,帮助排查错误。

5.实战示例:nuttx_add_subdirectory

5.1.nuttx_add_subdirectory简介

        nuttx_add_subdirectory 并非 CMake 标准命令,而是 NuttX RTOS(嵌入式实时操作系统) 项目中自定义的 CMake 函数,专门用于适配 NuttX 的模块化构建体系。其核心作用是:在 NuttX 构建流程中添加子目录(如驱动、应用、内核组件),并自动处理 NuttX 特有的配置依赖(Kconfig)、编译规则(嵌入式交叉编译)和模块间依赖,确保子目录模块与 NuttX 系统无缝集成。

        nuttx_add_subdirectory 的具体实现位于 NuttX 源码的 nuttx/cmake/NuttXFunctions.cmake 文件中,可通过查看该文件了解细节(如参数解析逻辑、配置依赖判断代码)。例如,核心逻辑片段(简化):

# nuttx/cmake/NuttXFunctions.cmakefunction(nuttx_add_subdirectory subdir_path)# 解析参数(MODULE、DEPENDS、CONFIG)cmake_parse_arguments(ARG"""MODULE;CONFIG""DEPENDS"${ARGN})# 检查 CONFIG 宏:未定义则跳过子目录if(ARG_CONFIG AND NOT DEFINED ${ARG_CONFIG})message(STATUS "Skip subdirectory ${subdir_path} (${ARG_CONFIG} not enabled)")return()endif()# 处理依赖模块:确保依赖先编译if(ARG_DEPENDS)foreach(dep ${ARG_DEPENDS})if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dep}/CMakeLists.txt)message(FATAL_ERROR "Dependency ${dep} not found for ${subdir_path}")endif()nuttx_add_subdirectory(${dep})  # 递归集成依赖模块endforeach()endif()# 执行标准 add_subdirectory(核心:加载子目录 CMakeLists.txt)add_subdirectory(${subdir_path})# 打印日志(含模块名称)set(module_name ${ARG_MODULE})if(NOT module_name)get_filename_component(module_name ${subdir_path} NAME)endif()message(STATUS "Added NuttX module: ${module_name} (path: ${subdir_path})")
endfunction()

nuttx_add_subdirectory 的语法由 NuttX 定义(不同版本略有差异,以 NuttX 11.0+ 为例),核心参数格式如下:

nuttx_add_subdirectory(<subdir_path>          # 1. 必选:子目录路径(相对 NuttX 根目录或当前 CMakeLists.txt 路径)[MODULE <module_name>] # 2. 可选:模块名称(用于日志和依赖标识,默认用子目录名)[DEPENDS <deps...>]    # 3. 可选:依赖的其他模块(如 "drivers/bus" "kernel/sched")[CONFIG <config_key>]  # 4. 可选:Kconfig 开关宏(如 "CONFIG_MY_DRIVER",未定义则不编译该子目录)
)

参数详解:

参数作用说明示例
<subdir_path>子目录的路径(如 drivers/uartapps/my_app),需包含 CMakeLists.txtnuttx_add_subdirectory(drivers/uart)
MODULE <name>给模块命名(便于日志区分),默认用子目录名(如 uart)。MODULE uart_driver
DEPENDS <deps>该模块依赖的其他 NuttX 模块(确保依赖模块先编译)。DEPENDS drivers/bus kernel/irq
CONFIG <key>控制模块是否启用的 Kconfig 宏(如 CONFIG_UART),若 /.config 中该宏未定义(或为 n),则跳过子目录。CONFIG CONFIG_UART

5.2.背景:NuttX 的模块化构建体系

NuttX 采用 “配置 - 构建” 分离的模块化设计,核心特点包括:

1.Kconfig 配置系统:通过 Kconfig 文件定义模块的可配置选项(如 “是否启用 UART 驱动”“是否支持 FAT 文件系统”),用户通过 menuconfig 选择后生成 /.config 配置文件。

2.CMake 构建系统:基于 CMake 实现跨平台交叉编译,自动根据 /.config 生成的宏(如 CONFIG_UART=y)决定是否编译某模块、链接哪些依赖。

3.子目录模块化:功能模块(驱动、应用、内核组件)按目录拆分(如 drivers/uartapps/systemkernel/sched),每个模块需通过特定函数集成到整体构建中 ——nuttx_add_subdirectory 就是为此设计的 “模块集成入口”。

5.3.nuttx_add_subdirectory 的核心作用

相比 CMake 标准命令 add_subdirectory(仅执行子目录的 CMakeLists.txt),nuttx_add_subdirectory 额外处理了 NuttX 特有的构建逻辑,核心功能包括:

1.Kconfig 配置依赖检查:根据 /.config 中的宏(如 CONFIG_MY_MODULE)判断是否启用该子目录模块,未启用则跳过编译。

2.自动传递 NuttX 编译环境:向子目录传递 NuttX 的交叉编译工具链、内核头文件路径、硬件平台宏(如 CONFIG_ARCH_ARMCONFIG_BOARD_STM32F4DISCO)。

3.模块依赖管理:自动处理子目录模块对 NuttX 内核 API(如线程、信号量)或其他模块(如驱动依赖总线框架)的依赖,确保编译顺序和链接正确性。

4.嵌入式编译规则适配:默认添加 NuttX 嵌入式编译选项(如 -ffunction-sections-fdata-sections 减小固件体积),兼容 NuttX 的链接脚本和内存布局。

5.4.实战示例:使用 nuttx_add_subdirectory 集成模块

以 “在 NuttX 中添加自定义 UART 驱动子目录” 和 “添加应用程序子目录” 为例,演示具体用法。

示例 1:添加自定义驱动子目录(drivers/my_uart

1.目录结构准备

首先在 NuttX 源码中创建自定义驱动目录,需包含 3 个核心文件:

nuttx/
└── drivers/└── my_uart/          # 自定义 UART 驱动子目录├── CMakeLists.txt # 驱动的构建配置├── Kconfig        # 驱动的配置选项(供 menuconfig 使用)├── my_uart.c      # 驱动源码└── my_uart.h      # 驱动头文件

2.父目录(drivers/CMakeLists.txt)调用 nuttx_add_subdirectory

在 NuttX 驱动根目录的 CMakeLists.txt 中,通过 nuttx_add_subdirectory 集成自定义驱动:

# nuttx/drivers/CMakeLists.txt# 集成标准 UART 驱动(NuttX 原生)
nuttx_add_subdirectory(drivers/uart MODULE uart CONFIG CONFIG_UART)# 集成自定义 UART 驱动(新增)
nuttx_add_subdirectory(my_uart                  # 子目录路径(相对当前 drivers/ 目录)MODULE my_uart_driver    # 模块名称DEPENDS drivers/bus kernel/irq  # 依赖:总线驱动、中断模块CONFIG CONFIG_MY_UART    # Kconfig 开关宏(需在 my_uart/Kconfig 中定义)
)

3.子目录(my_uart/CMakeLists.txt)编写

子目录的 CMakeLists.txt 需遵循 NuttX 驱动的构建规则(使用 NuttX 提供的编译函数):

# nuttx/drivers/my_uart/CMakeLists.txt# 1. 收集驱动源码
set(SRCS my_uart.c)# 2. 生成驱动库(NuttX 驱动通常编译为静态库,再链接到内核)
nuttx_add_library(my_uart_lib STATIC ${SRCS})# 3. 链接依赖(如内核 API、总线驱动)
target_link_libraries(my_uart_lib PRIVATE nuttx_kernel nuttx_bus)# 4. 添加内核头文件路径(NuttX 内核头文件在 include/ 目录)
target_include_directories(my_uart_lib PRIVATE ${CMAKE_SOURCE_DIR}/include)# 5. 将驱动库添加到 NuttX 全局链接列表(确保最终链接到固件)
list(APPEND NUTTX_DRIVERS_LIBS my_uart_lib)
set(NUTTX_DRIVERS_LIBS ${NUTTX_DRIVERS_LIBS} PARENT_SCOPE)

4.Kconfig 配置(my_uart/Kconfig

定义驱动的开关选项(供 menuconfig 配置),确保 CONFIG_MY_UART 宏能被 nuttx_add_subdirectory 识别:

# nuttx/drivers/my_uart/Kconfigconfig MY_UARTbool "Enable Custom UART Driver"default ndepends on ARCH_HAS_UART  # 依赖硬件平台支持 UARThelpEnable support for custom UART driver (for STM32F4xx).

示例 2:添加应用程序子目录(apps/my_app

NuttX 的 apps/ 目录存放用户应用,集成方式与驱动类似:

# nuttx/apps/CMakeLists.txt# 集成自定义应用(my_app)
nuttx_add_subdirectory(my_app                  # 应用子目录路径MODULE my_application   # 模块名称DEPENDS system/stdio    # 依赖:标准输入输出模块CONFIG CONFIG_MY_APP    # Kconfig 开关宏
)

子目录 apps/my_app/CMakeLists.txt 编写(应用通常编译为可执行文件或链接到 apps 库):

# nuttx/apps/my_app/CMakeLists.txtset(SRCS my_app_main.c)# 编译应用为可执行文件(NuttX 应用支持静态链接到内核或动态加载)
nuttx_add_executable(my_app ${SRCS})# 链接依赖(如标准库、NuttX 应用框架)
target_link_libraries(my_app PRIVATE nuttx_apps nuttx_stdio)# 添加头文件路径
target_include_directories(my_app PRIVATE ${CMAKE_SOURCE_DIR}/include)

5.5.关键区别:nuttx_add_subdirectory vs 标准 add_subdirectory

特性nuttx_add_subdirectory(NuttX 自定义)add_subdirectory(CMake 标准)
配置依赖处理支持 Kconfig 开关宏(CONFIG <key>),未启用则跳过子目录无配置依赖,强制执行子目录 CMakeLists.txt
编译环境传递自动传递 NuttX 交叉编译工具链、内核宏、硬件平台选项仅继承父目录的 CMake 环境,需手动配置嵌入式编译选项
模块依赖管理支持 DEPENDS 参数,确保依赖模块先编译无依赖管理,需手动通过 add_dependencies 控制编译顺序
嵌入式规则适配默认添加 NuttX 嵌入式编译选项(如 -ffunction-sections)、链接脚本支持无嵌入式适配,需手动编写交叉编译规则
适用场景NuttX 内核模块、驱动、应用的集成通用 CMake 项目的子目录管理(非嵌入式 / 非 NuttX 场景)

6.注意事项

1.PREFIX 必须唯一,避免变量污染

不同函数的 PREFIX 不能重复(如两个函数都用 PARSE 作为前缀,会导致变量覆盖)。推荐用函数名相关的前缀(如 add_my_executable 用 MY_EXE)。

2.参数顺序不强制,但推荐 “位置参数在前,关键字参数在后”

CMake 允许关键字参数穿插在位置参数中(如 add_my_executable(prjXiAn SOURCES main.cpp OUTPUT_DIR bin)),但为了可读性,建议按 “位置参数 → 开关参数 → 单值参数 → 多值参数” 的顺序传递。

3.单值参数必须跟值,多值参数可跟多个值

  • 单值参数(如 OUTPUT_DIR)若未跟值,CMake 会报错:cmake_parse_arguments called with incorrect number of arguments for ONE_VALUE_ARGS
  • 多值参数(如 DEPENDS)若未跟值,MY_EXE_DEPENDS 会是空列表(不会报错)。

4.大小写不敏感,但推荐统一风格

CMake 对关键字参数不区分大小写(如 with_debug 和 WITH_DEBUG 等效),但为了代码规范,建议统一使用大写(如 WITH_DEBUGOUTPUT_DIR)。

5.捕获未解析参数,排查错误

cmake_parse_arguments 会自动生成 PREFIX_UNPARSED_ARGUMENTS 变量,存储未匹配到任何规则的参数。建议在函数中检查该变量并打印警告(如示例中的 if(MY_EXE_UNPARSED_ARGUMENTS)),避免因误传参数导致隐藏问题。

6.CMake 版本兼容性

cmake_parse_arguments 从 CMake 3.5 版本开始支持,若项目需兼容更低版本(如 3.4 及以下),需改用手动解析 ARGN 的方式(通过循环判断参数类型,代码繁琐,不推荐)。

7.总结

cmake_parse_arguments 是编写复杂自定义函数 / 宏的必备工具,尤其适合以下场景:

1.封装 add_executable/add_library,支持自定义输出目录、编译开关、依赖库(如示例中的 add_my_executable);

2.处理第三方库的配置函数(如 find_package 后的自定义初始化函数,支持多参数配置);

3.编写通用工具函数(如文件复制、批量编译,需要灵活的参数输入)。

通过它,你可以摆脱手动循环 ARGN 解析参数的繁琐工作,让自定义函数的参数逻辑更清晰、更易维护,同时兼顾跨平台兼容性(如配合 cmake_path 处理路径)。

相关链接

  • CMake 官网 https://cmake.org/
  • CMake 官方文档:https://cmake.org/cmake/help/latest/guide/tutorial/index.html
  • CMake 源码:https://github.com/Kitware/CMake
  • CMake 源码:https://gitlab.kitware.com/cmake/cmakeku
  • 中文版基础介绍: https://www.hahack.com/codes/cmake/
  • wiki: https://gitlab.kitware.com/cmake/community/-/wikis/Home
  • Modern CMake 简体中文版:  https://modern-cmake-cn.github.io/Modern-CMake-zh_CN/
http://www.dtcms.com/a/458399.html

相关文章:

  • 中山市 有限公司网站建设页面设计制作网站
  • 洛宁县东宋乡城乡建设局网站怎样维护公司网站
  • 最新Kolmogorov-Arnold网络架构下的KANConv
  • 【C语言操作符终极指南】万字总结:从二进制到表达式求值,全方位解析+避坑指南
  • 大模型-扩散模型(Diffusion Model)原理讲解(5)
  • 基于51单片机的多功能电子万年历
  • iis中的网站启动不了湖南省郴州市宜章县邮政编码
  • 镇江网站建设活动方案c 做网站源码实例
  • 网站网页能自己做吗甘肃省建设稽查执法局网站
  • 家电维修企业网站源码台州椒江找人做网站
  • 小公司做网站wordpress login插件
  • 苏州网站建设最好网络安全监测服务
  • 曹妃甸网站建设flex网站模板
  • 语义通信:从“传比特”到“传意义”的范式迁移
  • 150网站建设宜昌怎样优化网站建设
  • 现在网站开发模式广州网站建设培训
  • 西门子产品完全卸载工具
  • wordpress添加媒体失败福建优化seo
  • 浙江省住房城乡建设厅网站网站备案截图
  • 从information被ban到无列名注入
  • 吉林律师网站建设多少钱自己弄个网站怎么赚钱
  • 360网站如何做引流网址推广工具有哪些
  • wordpress图片后加载很慢新网站怎么做seo
  • 零售户订烟电商网站高清的宝安网站推广
  • 官网设计房产中山市企业网站seo营销工具
  • 一站式服务大厅自己做网站 套模板
  • 网站设计 站想学做网站学什么编程语言
  • 建网站html5wordpress文章展示相册
  • 公司网站怎么登录请问番禺哪里有做网站的
  • wordpress在哪设置评论三门峡seo