CMake RULE_LAUNCH_CUSTOM 目录属性详解:为自定义规则命令注入启动器
构建工具开发工具CLI【免费下载链接】CMakeMirror of CMake upstream repository项目地址https://gitcode.com/gh_mirrors/cm/CMake点击查看免费下载导读RULE_LAUNCH_CUSTOM是 CMake 中用于指定自定义规则启动器launcher的目录属性它可以让 Makefile 系生成器与 Ninja 生成器在真正执行每一条自定义命令如add_custom_command/add_custom_target产生的规则之前先以前缀方式插入一条包装命令。本文基于 CMake 官方文档与源码实现完整讲解该属性的语义、生效范围、跨生成器差异、占位符展开机制以及典型应用场景构建问题拦截、ctest 仪表盘错误上报、构建行为插桩帮助你准确判断该不该用、怎么用、用了会有什么效果。属性语义为自定义规则指定一个启动器按照 Help/prop_dir/RULE_LAUNCH_CUSTOM.rst 的定义Specify a launcher for custom rules. 为自定义规则指定一个启动器。 See the global property of the same name for details. This overrides the global property for a directory.同名全局属性的详细说明见全局属性文档本属性会覆盖全局同名属性作用范围限定在当前目录。它与 全局属性 RULE_LAUNCH_CUSTOM 的关系是目录级覆盖全局级全局属性在 CMake 顶层目录设置作用于整个项目目录属性在某一个add_subdirectory子目录或当前目录范围内设置只影响该目录及其未另行覆盖的子目录中的自定义规则两个作用域同名共存时目录属性优先。所谓自定义规则custom rules在 CMake 语境中指由add_custom_command、add_custom_target、file(GENERATE)等命令生成、并最终落到构建系统里的命令规则它们与编译规则、链接规则并列分别由三个RULE_LAUNCH_*属性控制属性作用对象内部用途说明RULE_LAUNCH_CUSTOM自定义规则custom commands本文主题拦截任意自定义命令RULE_LAUNCH_COMPILE编译规则compile rules官方文档标注仅供ctest(1)内部使用项目开发者应改用LANG_COMPILER_LAUNCHER目标属性见 全局属性 RULE_LAUNCH_COMPILERULE_LAUNCH_LINK链接/归档规则link archive rules同样标注仅供ctest(1)内部使用开发者应改用LANG_LINKER_LAUNCHER见 全局属性 RULE_LAUNCH_LINK注意RULE_LAUNCH_COMPILE与RULE_LAUNCH_LINK的文档都明确建议普通项目不要直接使用而是使用CMAKE_LANG_COMPILER_LAUNCHER、CMAKE_LANG_LINKER_LAUNCHER变量或对应的目标属性。但RULE_LAUNCH_CUSTOM没有这一限制——因为自定义命令没有对应的编译器启动器等价物它至今仍是包裹自定义规则的标准手段。生成器支持范围并非所有生成器都生效全局属性文档明确说明了支持范围Makefile Generators和Ninja生成器会用给定的启动器命令行作为自定义命令的前缀。这样做的目的是让启动器能够以高粒度拦截构建问题。其他生成器会忽略该属性因为它们的底层构建系统没有提供包装单条命令的钩子。也就是说生效所有 Makefile 系生成器Unix Makefiles、NMake Makefiles、MinGW Makefiles、MSYS Makefiles 等以及 Ninja含 Ninja Multi-Config同样生效从源码看cmFastbuildTargetGenerator.cxx 中的MakeCustomLauncher也读取RULE_LAUNCH_CUSTOM属性注释明确写着 Copied from cmLocalNinjaGenerator::MakeCustomLauncher因此 FASTBuild 生成器同样支持忽略Visual Studio、Xcode 等其他生成器因为它们无法把单条规则单独包一层启动器。这一差异在排障时非常关键同一个项目在 Unix Makefiles 下启动器生效切换到 Visual Studio 生成器后该属性会被静默忽略不能依赖它做与平台无关的强制拦截。属性链与作用域解析目录如何覆盖全局从源码看RULE_LAUNCH_*三个属性在 cmState.cxx 中被同时注册为目录DIRECTORY与目标TARGET两个作用域的属性且都是链式chained属性this-DefineProperty(RULE_LAUNCH_CUSTOM, cmProperty::DIRECTORY, , , true); // ... this-DefineProperty(RULE_LAUNCH_CUSTOM, cmProperty::TARGET, , , true);而目录属性的实际取值解析发生在cmLocalGenerator::GetRuleLaunchercmLocalGenerator.cxxstd::string cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, std::string const prop, std::string const config) { cmValue value this-Makefile-GetProperty(prop); if (target) { value target-GetProperty(prop); // 目标属性优先 } if (value) { return cmGeneratorExpression::Evaluate(*value, this, config, target); } return ; }可以总结出三层取值规则先取目录属性GetProperty本身会沿目录作用域链向上查找所以子目录未设置时会继承父目录的值若存在目标再取目标属性并覆盖目录属性返回值会经过生成器表达式generator expression求值因此属性值里可以写$CONFIG等表达式。目录属性文档中覆盖全局属性overrides the global property for a directory正是这一解析链在目录一级的具体体现目录级值优先于 全局属性 中的值。底层实现启动器如何被展开并拼接到命令前Ninja 生成器Ninja 生成器在 cmLocalNinjaGenerator.cxx 的MakeCustomLauncher中实现cmValue property_value this-Makefile-GetProperty(RULE_LAUNCH_CUSTOM); if (!cmNonempty(property_value)) { return std::string(); // 未设置则返回空 } // 展开规则变量rule variables cmRulePlaceholderExpander::RuleVariables vars; // ... 收集 outputs逗号分隔后存入 vars.Output ... vars.Output output.c_str(); vars.FilePathWithOutput ccg.StoreContentToFile(output).c_str(); vars.Role ccg.GetCC().GetRole().c_str(); vars.CMTargetName ccg.GetCC().GetTarget().c_str(); vars.Config ccg.GetOutputConfig().c_str(); std::string launcher *property_value; rulePlaceholderExpander-ExpandRuleVariables(this, launcher, vars); if (!launcher.empty()) { launcher ; // 拼接时在启动器后补一个空格 } return launcher;其行为要点属性值为空时直接返回空串不产生任何前缀属性值中的OUTPUT、OUTPUT_STORE_TO_FILE、ROLE、TARGET_NAME、CONFIG等占位符会被逐一展开展开完成后在启动器末尾补一个空格再拼接到真正的自定义命令之前。Makefile 生成器Unix Makefile 系生成器在 cmLocalUnixMakefileGenerator3.cxx 中走同样的路径且使用了GetRuleLauncher统一入口std::string launcher; std::string val this-GetRuleLauncher( target, RULE_LAUNCH_CUSTOM, this-Makefile-GetSafeDefinition(CMAKE_BUILD_TYPE)); if (cmNonempty(val)) { // 展开规则变量TARGET_SUPPORT_DIR、CMTargetName、CMTargetType、 // Output、FilePathWithOutput、Role、Config 等 ... } // ... std::string shellCommand this-ConvertToOutputFormat(cmd, cmOutputConverter::SHELL); cmd launcher shellCommand; // 启动器 真正命令Makefile 实现与 Ninja 基本一致另有两点细节vars.TargetSupportDir会被设置为cmTarget::GetCMFSupportDirectory对应的支持目录见 cmLocalUnixMakefileGenerator3.cxx因此TARGET_SUPPORT_DIR占位符在 Makefile 生成器下可用拼接后的命令若以相对路径引用当前目录下的程序生成器会自动补./前缀见 cmLocalUnixMakefileGenerator3.cxx避免当前目录不在 PATH 中时执行失败。启动器值中可用的占位符启动器属性值本质上是一段命令模板CMake 会按规则变量rule variables展开。与自定义规则启动器直接相关的占位符包括占位符含义可用性OUTPUT规则输出文件列表多个以逗号分隔shell 转义后Ninja / Makefile / FASTBuildOUTPUT_STORE_TO_FILE把输出列表写入临时文件后得到的文件路径StoreContentToFileNinja / Makefile / FASTBuildROLE自定义命令的角色如CUSTOM_COMMAND相关角色标识Ninja / Makefile / FASTBuildTARGET_NAME关联目标的名称Ninja / Makefile / FASTBuildCONFIG当前构建配置如 Debug/ReleaseNinja / MakefileTARGET_SUPPORT_DIR目标支持目录CMake 生成辅助文件的目录Makefile 系生成器CMAKE_CURRENT_BINARY_DIR当前二进制目录由外部调用方注入见下文 ctest 插桩这些占位符的集合定义在 cmRulePlaceholderExpander.h 的RuleVariables结构体中其中与本文相关的字段包括Output、FilePathWithOutput、TargetSupportDir、CMTargetName、CMTargetType、Config、Role等。一个带占位符的典型取值示例set_property(DIRECTORY PROPERTY RULE_LAUNCH_CUSTOM \${CMAKE_COMMAND}\ -E echo \running custom rule for TARGET_NAME: OUTPUT\ -- )实战配置目录级、全局级与目标级设置目录级本文主题在某个子目录的 CMakeLists.txt 中# 仅对本目录及其子目录中的自定义规则生效 set_property(DIRECTORY PROPERTY RULE_LAUNCH_CUSTOM \${CMAKE_COMMAND}\ -E echo \[custom] \ -- )更实用的写法——用自定义脚本做记录/校验set_property(DIRECTORY PROPERTY RULE_LAUNCH_CUSTOM ${CMAKE_COMMAND} -E env WRAPPER_MARKERcustom ${CMAKE_COMMAND} -- )全局级在顶层 CMakeLists.txt 中设置全局同名属性作为整个项目所有目录的默认值set_property(GLOBAL PROPERTY RULE_LAUNCH_CUSTOM \${CMAKE_COMMAND}\ -E echo \[global custom launcher] \ -- )目标级属性同时在目标作用域注册见上文 cmState.cxx可以只包裹某个目标的规则set_property(TARGET my_target PROPERTY RULE_LAUNCH_CUSTOM \${CMAKE_COMMAND}\ -E echo \[target custom launcher] \ -- )三个层级同时存在时解析顺序为目标级 目录级 全局级。注意事项启动器值中建议对路径和可执行文件加引号防止路径含空格时被 shell 拆分属性值会被当作命令模板拼接不要在其中以分号列表形式混入多条命令否则会被 CMake 当作参数列表处理而非一整条模板使用前先确认当前生成器属于生效列表Makefile 系、Ninja、FASTBuild否则设置会被静默忽略需要按配置区分的场景可在值中嵌入生成器表达式因为 cmLocalGenerator.cxx 会对最终值执行cmGeneratorExpression::Evaluate。典型应用场景从 ctest 仪表盘到构建插桩场景一拦截自定义规则的构建问题全局属性文档指出该机制旨在让启动器以高粒度拦截构建问题。典型做法是让启动器记录每条自定义规则的执行时间、退出码、输出日志当规则失败时把详细信息写入诊断文件供构建仪表盘dashboard汇总。场景二ctest 启动器与仪器化插桩ctest --launch / --instrument这是 CMake 内部对RULE_LAUNCH_CUSTOM最直接的使用。在 cmake.cxx 中当CTEST_USE_LAUNCHERS开启或存在仪器化查询instrumentation query时CMake 会自动写入三个全局RULE_LAUNCH_*属性其中自定义规则部分为this-State-SetGlobalProperty( RULE_LAUNCH_CUSTOM, cmStrCat( launcher, --command-type custom, common_args, --output-as-file-name \OUTPUT_STORE_TO_FILE\ --role ROLE -- ));launcher由CTEST_USE_LAUNCHERS决定是ctest --launch ...还是ctest --instrument ...common_args中包含--target-name TARGET_NAME --config CONFIG --build-dir ...。换句话说当启用 ctest 启动器/插桩后你可以在生成的构建命令中看到类似这样的前缀/path/to/ctest --launch --command-type custom \ --target-name TARGET_NAME --config CONFIG --build-dir /path/to/build \ --output-as-file-name OUTPUT_STORE_TO_FILE --role ROLE -- 原始自定义命令这正是 RULE_LAUNCH_CUSTOM 作为构建问题高粒度拦截钩子的设计意图的直接体现每条自定义规则都能被单独包装、单独记录结果。测试侧对ctest --launch/ctest --instrument的退出码分类成功、非零退出、信号终止、无法 spawn 等可参考 Tests/RunCMake/CTestLaunch/RunCMakeTest.cmake 中的回归用例。场景三构建过程插桩与分析可以借助启动器为自定义命令注入环境变量、计时、资源统计或日志采集实现对每条规则逐一插桩的细粒度观测——这是全局性包装工具如对整个构建做 strace难以做到的。由于该机制只影响自定义规则而非编译/链接规则插桩范围精确可控不会干扰编译器与链接器的调用路径。与其他启动器类属性的边界属性覆盖的规则推荐给普通项目RULE_LAUNCH_CUSTOM自定义命令规则是无等价替代物RULE_LAUNCH_COMPILE编译规则否应改用LANG_COMPILER_LAUNCHER/CMAKE_LANG_COMPILER_LAUNCHER见 Help/prop_gbl/RULE_LAUNCH_COMPILE.rstRULE_LAUNCH_LINK链接/归档规则否应改用LANG_LINKER_LAUNCHER/CMAKE_LANG_LINKER_LAUNCHER见 Help/prop_gbl/RULE_LAUNCH_LINK.rst简言之编译与链接有现代的专用启动器属性LANG_COMPILER_LAUNCHER、LANG_LINKER_LAUNCHER而自定义规则只有RULE_LAUNCH_CUSTOM这一个官方入口因此它的使用场景至今仍然成立。小结RULE_LAUNCH_CUSTOM为自定义规则指定启动器目录级设置会覆盖同名 全局属性目标级设置又优先于目录级仅在 Makefile 系生成器、Ninja 与 FASTBuild 下生效其他生成器忽略该属性属性值支持OUTPUT、OUTPUT_STORE_TO_FILE、ROLE、TARGET_NAME、CONFIG、TARGET_SUPPORT_DIR等规则占位符并支持生成器表达式底层由cmLocalGenerator::GetRuleLaunchercmLocalGenerator.cxx统一解析Ninja 与 FASTBuild 在MakeCustomLauncher中、Makefile 系在WriteRule相关流程中完成拼接ctest 的启动器与插桩机制ctest --launch/--instrument正是通过自动设置该属性来实现对每条自定义命令的拦截与结果分类相关回归测试见 Tests/RunCMake/CTestLaunch/RunCMakeTest.cmake。参考资料目录属性文档 Help/prop_dir/RULE_LAUNCH_CUSTOM.rst、全局属性文档 Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst 及其实现源码 cmLocalNinjaGenerator.cxx、cmLocalUnixMakefileGenerator3.cxx、cmFastbuildTargetGenerator.cxx、cmState.cxx。赞分享构建工具开发工具CLI【免费下载链接】CMakeMirror of CMake upstream repository项目地址https://gitcode.com/gh_mirrors/cm/CMake点击查看免费下载相关推荐CMake 目录属性 TEST_INCLUDE_FILES向 ctest 注入自定义 CMake 脚本的机制与实践CMake 目录属性 TEST_INCLUDE_FILES向 ctest 注入自定义 CMake 脚本的机制与实践 TEST_INCLUDE_FILES 是构建工具开发工具CLICMake VS_GLOBAL_SECTION_POST_section 目录属性向 Visual Studio 解决方案文件注入自定义 GlobalSectionCMake VS_GLOBAL_SECTION_POST_section 目录属性向 Visual Studio 解决方案文件注入自定义 GlobalSec构建工具开发工具CLICMake 4.5 新特性详解用 RULE_PATTERNS 文件集属性驱动自定义规则的占位符展开CMake 4.5 新特性详解用 RULE_PATTERNS 文件集属性驱动自定义规则的占位符展开 本篇围绕 CMake 的文件集属性 RULE_PATTER构建工具开发工具CLI上一篇如何用PHP打造高颜值二维码chillerlan/php-qrcode终极教程下一篇Apache Beam Java Katas 实战使用 Sum 变换对 PCollection 元素求和Aggregation · Sum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考