CMake实战指南一:add_custom_command

CMake 进阶:add_custom_command 用法详解与实战指南

在 CMake 构建系统中,add_custom_command 是一个灵活且强大的工具,允许开发者在构建流程中插入自定义操作。无论是生成中间文件、执行预处理脚本,还是在目标构建前后触发额外逻辑,它都能轻松胜任。本文将从基础语法、核心参数、实战案例到高级技巧,全面解析 add_custom_command 的用法。

一、为什么需要 add_custom_command

CMake 的核心优势在于跨平台构建,但默认流程难以覆盖所有个性化需求。例如:

  • 生成动态配置文件(如根据编译选项生成 config.h
  • 集成外部工具链(如代码生成器、静态分析工具)
  • 构建后处理(如复制可执行文件到部署目录、生成版本号)
  • 复杂依赖管理(非传统文件依赖的场景)

add_custom_command 正是为解决这类问题而生,它通过在构建流程中注入自定义命令,让 CMake 具备更强的扩展性。

二、基础语法与核心参数

2.1 两大使用场景

场景 1:生成文件(File Generation)

用于定义 “输入文件→输出文件” 的映射关系,CMake 会根据依赖自动触发命令:

add_custom_command(  

    OUTPUT <output1> [<output2>...]  # 必选:命令生成的目标文件  

    COMMAND <command1> [<args1>...]   # 必选:执行的命令(可多条)  

    [MAIN_DEPENDENCY <file>]           # 主依赖文件(变化时强制重新执行)  

    [DEPENDS <dep1> <dep2>...]        # 附加依赖文件/目标(变化时触发重新执行)  

    [IMPLICIT_DEPENDS <lang> <file>]   # 隐式依赖(如语法分析生成的依赖)  

    [WORKING_DIRECTORY <dir>]          # 命令执行的工作目录(默认当前源目录)  

    [COMMENT "<message>"]              # 执行时显示的提示信息  

    [VERBATIM]                         # 保留命令原始格式(避免CMake转义)  

    [USES_TERMINAL]                    # 在终端中执行命令(Windows适用)  

)  

场景 2:关联构建目标(Target Hook)

用于在目标(可执行文件 / 库)的构建阶段插入钩子:

-- Cmake version: 4.1.2. -- Setting build type to 'Debug' as none was specified. -- Build uses 8 processors -- Configuring -- The C compiler identification is GNU 9.4.0 -- The CXX compiler identification is GNU 9.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done CMake Error at CMakeLists.txt:40 (add_subdirectory): add_subdirectory given source "opencpn-libs/api-16" which is not an existing directory. CMake Error at CMakeLists.txt:54 (string): string sub-command REGEX, mode REPLACE needs at least 6 arguments total to command. -- Building for target:release ubuntu-x86_64:20.04 -- Metadata.cmake: git_hash=129a3eeb git_tag= -- Selected upload repository: o p e n c p n - r a d a r - p i / r a d a r - u n s t a b l e CMake Warning (dev) at cmake/Targets.cmake:151 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:253 (tarball_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:156 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:253 (tarball_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:160 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:253 (tarball_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:175 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:254 (flatpak_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:237 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:254 (flatpak_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:117 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:255 (android_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:121 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:255 (android_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning (dev) at cmake/Targets.cmake:125 (add_custom_command): Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming POST_BUILD to preserve backward compatibility. Policy CMP0175 is not set: add_custom_command() rejects invalid arguments. Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy command to set the policy and suppress this warning. Call Stack (most recent call first): cmake/Targets.cmake:255 (android_target) CMakeLists.txt:73 (create_targets) This warning is for project developers. Use -Wno-dev to suppress it. -- Configuring incomplete, errors occurred!
最新发布
10-21
<think>我们正在解决编译radar_pi插件时遇到的CMake错误。用户报告了三个主要问题: 1. add_subdirectory指定的源目录不存在 2. string命令参数不足 3. add_custom_command参数使用不当 环境:Ubuntu 20.04 由于radar_pi插件的构建通常需要特定的依赖和正确的CMake配置,我们将逐分析这些错误并提供解决方案。 步骤: 1. 确认源码目录结构 2. 修复add_subdirectory错误(通常是因为缺失子模块) 3. 修复string命令错误(检查CMakeLists.txt中的string命令格式) 4. 修复add_custom_command错误(检查参数是否完整) 5. 重新配置和构建 详细步骤: 1. 获取完整源码并初始化子模块 radar_pi插件使用git子模块来管理部分依赖(如Pango和Cairo的封装库)。如果未初始化子模块,则add_subdirectory会失败。 2. 检查并修复CMakeLists.txt中的问题 - 对于string命令,确保其使用正确的语法,例如:string(APPEND ...) 需要两个参数。 - 对于add_custom_command,检查其参数是否满足要求(例如,必须指定OUTPUT和COMMAND)。 3. 确保CMake版本满足要求。radar_pi可能需要较新版本的CMake。 4. 环境设置:设置正确的OpenCPN开发文件路径。 具体操作: 第步:初始化子模块 ```bash cd ~/opencpn_plugins/radar_pi git submodule init git submodule update ``` 第二步:检查CMakeLists.txt中的问题(可能需要手动修改) - 错误1:add_subdirectory源目录不存在 可能原因:子模块未拉取,或路径错误。 解决:如上初始化子模块。 - 错误2:string命令参数不足 在CMakeLists.txt中查找string命令,例如: string(APPEND ...) 需要两个参数:变量名和要追加的字符串。例如: string(APPEND MY_VAR "additional string") - 错误3:add_custom_command参数使用不当 检查add_custom_command的调用,确保至少指定了OUTPUT和COMMAND。例如: add_custom_command(OUTPUT output_file COMMAND my_command args DEPENDS input_file) 注意:在CMake 3.0及以上版本,add_custom_command有更严格的参数检查。 第三步:升级CMake(如果需要) Ubuntu 20.04默认的CMake版本是3.16.3,但radar_pi可能需要更高版本。我们可以通过Kitware仓库安装最新版CMake。 ```bash sudo apt remove --purge cmake sudo apt install software-properties-common sudo add-apt-repository -y ppa:kitware/archive sudo apt update sudo apt install cmake ``` 第四步:重新配置和构建 ```bash cd build cmake .. -DOCPN_DIR=/path/to/your/opencpn/build # 替换为你的OpenCPN构建路径 make -j$(nproc) ``` 如果问题仍然存在,请提供具体的错误信息,我们可以更针对性地修复。 常见问题补充: - 如果出现关于Pango组件的错误,可能需要安装pkg-config: sudo apt install pkg-config - 如果缺少其他依赖,根据错误提示安装相应的开发包。 示例修复string命令: 原始错误行: string(APPEND) 修正为: string(APPEND MY_STRING_VARIABLE "some text") 示例修复add_custom_command: 原始错误行: add_custom_command(OUTPUT output_file) 修正:(需要添加COMMAND和可能的DEPENDS) add_custom_command(OUTPUT output_file COMMAND touch output_file DEPENDS input_file) 注意:这些修改可能需要直接编辑CMakeLists.txt文件。建议先备份。 如果用户遇到特定行号的错误,可以指定修改。 相关问题: 1. 如何正确处理git子模块? 2. 如何升级CMake并管理多个版本? 3. 如何调试CMake脚本的错误? 4. 在Ubuntu中如何安装Pango和Cairo的开发包? 5. CMakeadd_custom_command的正确用法是什么?[^1] 我们将按照上述步骤进行操作。 </think>### 解决 OpenCPN radar_pi 插件编译中的 CMake 错误(Ubuntu 20.04) 以下是针对您遇到的 CMake 错误的具体解决方案,按照问题分类: --- #### ️ 1. **add_subdirectory 源目录不存在** **错误原因**: 通常是因为 Git 子模块未初始化或 CMake 路径配置错误。 **解决方案**: ```bash cd ~/opencpn_plugins/radar_pi # 初始化并更新子模块 git submodule init git submodule update # 检查缺失的目录(通常是第三方依赖) ls -l plugins/draw_pi plugins/weather_routing_pi # 验证子模块是否存在 ``` **关键点**: - 如果子模块仍缺失,手动克隆: ```bash git clone https://github.com/opencpn-radar-pi/draw_pi.git plugins/draw_pi ``` --- #### 2. **string 命令参数不足** **错误原因**: CMakeLists.txt 中 `string()` 函数调用格式错误,常见于变量替换操作。 **修复步骤**: 1. 打开出错的 CMakeLists.txt 文件(通常在主目录或插件目录) 2. 查找类似代码: ```cmake string(CONCAT ...) # 缺少参数 ``` 3. 修正为: ```cmake string(CONCAT OUTPUT_VAR "part1" "part2") # 确保有输出变量和至少两个输入 ``` **实际案例**: 在 `radar_pi/CMakeLists.txt` 中替换: ```cmake # 错误示例 string(APPEND) # 正确示例 string(APPEND CMAKE_CXX_FLAGS " -Wall") ``` --- #### ️ 3. **add_custom_command 参数不当** **错误原因**: 缺少必要的 `OUTPUT` 或 `COMMAND` 声明,或目标文件路径错误。 **修复方法**: ```cmake # 错误示例 add_custom_command(TARGET radar_pi PRE_BUILD COMMAND echo "Building...") # 正确示例 add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/generated_file.h # 必须声明输出 COMMAND touch ${CMAKE_BINARY_DIR}/generated_file.h # 完整命令 DEPENDS source_file.txt # 明确依赖 COMMENT "Generating header file" # 可选注释 ) ``` **验证步骤**: 在 `build/` 目录运行: ```bash cmake --trace-expand .. | grep add_custom_command # 调试命令参数 ``` --- #### 🔧 完整编译流程修正 ```bash # 清理旧构建 rm -rf build && mkdir build && cd build # 配置时启用详细日志(定位错误) cmake .. -DOCPN_DIR=/path/to/opencpn \ # 替换为实际路径 -DCMAKE_VERBOSE_MAKEFILE=ON \ # 启用详细输出 --debug-output # CMake 调试模式 # 重新编译 make -j$(nproc) 2>&1 | tee build.log # 保存日志 ``` --- #### ⚡ 高级故障排除 1. **CMake 版本问题**(Ubuntu 20.04 默认 CMake 3.16): ```bash # 升级 CMake pip install cmake --upgrade # 或下载最新版 ``` 2. **依赖项缺失**: ```bash sudo apt install libpango1.0-dev libcairo2-dev # radar_pi 常见依赖 ``` 3. **路径硬编码修复**: 在 `CMakeLists.txt` 中替换所有 `include/` 为: ```cmake ${CMAKE_SOURCE_DIR}/include # 使用相对路径 ``` --- #### 📝 相关问题 1. 如何正确管理 Git 子模块在 CMake 项目中的依赖?[^1] 2. CMake 中 `add_custom_command` 和 `add_custom_target` 的区别是什么? 3. 如何为 OpenCPN 插件创建跨平台构建脚本? 4. Ubuntu 20.04 中升级 CMake 的安全方法有哪些? 5. CMake 调试日志中 `--trace-expand` 和 `--trace-source` 的区别?[^2] [^1]: Git 子模块管理最佳实践 [^2]: CMake 调试技巧指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

binary0010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值