关于 compile-analysis
面向 ACE Engine 开发者的编译分析技能,可测量单个源文件的编译耗时和峰值内存,并解析头文件依赖树。结果基于实际编译执行,支持保存脚本以便重复测试。
主要功能
- 01测量单文件编译时间与峰值内存
- 02从 ninja 构建文件提取编译命令
- 03解析并显示头文件依赖树
- 04生成可重复执行的编译脚本
适用场景
- 01定位编译耗时较长的源文件
- 02检查源文件的头文件依赖
- 03重复运行单文件编译以比较性能
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openharmonyinsight/ openharmony-skills --skill compile-analysis安装后在 Claude Code 中输入/compile-analysis确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdexamples/example-workflow.mdreferences/optimization.mdworkflow.mdscripts/analyze_compile.shget_compile_command.pyparse_ii.py详细介绍
编译效率分析技能
分析 ACE Engine 项目中单个源文件的编译效率。此技能可详细展示编译时间、资源开销和头文件依赖关系,帮助发现优化机会。
概述
编译分析通过测量以下指标,帮助识别构建过程中的性能瓶颈:
- 编译时间 - 编译一个文件所需的时间
- 资源开销 - 编译期间的峰值内存用量
- 头文件依赖 - 所包含头文件的树形结构
关键要求:
- ⚠️ 可在当前项目目录中执行 analyze_compile.sh 脚本
- ⚠️ 必须在
out/{product}目录中执行提取的编译命令(不能从项目根目录执行) - ⚠️ 所有分析结果必须基于实际执行,不得猜测或估算
- ⚠️ 必须使用内置的
parse_ii.py脚本解析头文件依赖并分析.ii文件——不得使用其他方法
在以下情况下使用此分析:
- 调查编译缓慢的问题
- 找出依赖过多的文件
- 优化构建性能
- 了解包含关系
分析工作流
步骤 1:定位源文件
确定要分析的目标源文件。ace_engine 中的源文件通常遵循以下路径格式:
frameworks/core/components_ng/base/frame_node.cppframeworks/bridge/declarative_frontend/engine/js_engine.cpp
步骤 2:查找 OpenHarmony 根目录
分析脚本会自动搜索 .gn 文件标记,以定位 OpenHarmony 根目录。请导航到 OpenHarmony 根目录,确保路径解析正确。
步骤 3:选择分析模式
选项 A:完整分析(执行并显示结果)
./.claude/skills/compile-analysis/scripts/analyze_compile.sh <source-file> [product-name]
示例:
./.claude/skills/compile-analysis/scripts/analyze_compile.sh frameworks/core/components_ng/base/frame_node.cpp rk3568
选项 B:保存可复用的编译脚本
生成可多次执行的独立脚本,用于性能测试:
./.claude/skills/compile-analysis/scripts/analyze_compile.sh <source-file> [product-name] --save-script
此操作会创建 out/{product}/compile_single_file_{name}.sh,其中包含:
- 自动环境设置
- 性能监控(时间和内存)
- 生成 .ii 和 .o 文件
- 可重复执行,以进行基准测试
步骤 4:解读结果
分析会生成三个关键输出:
- 编译命令 - 包含所有标志的完整编译器命令
- 性能指标:
- 耗时(格式:
MM:SS.mm) - 峰值内存用量,单位为 KB
- 耗时(格式:
- 依赖树 - 以层级结构展示头文件的包含关系
使用 --save-script 时,会生成可复用脚本,以便重复进行性能测试。
关键脚本
analyze_compile.sh(主脚本)
编译分析的主要入口,负责协调整个分析工作流:
用法:
# Full analysis with execution
./.claude/skills/compile-analysis/scripts/analyze_compile.sh <source-file> [product-name]
# Save standalone compilation script
./.claude/skills/compile-analysis/scripts/analyze_compile.sh <source-file> [product-name] --save-script
参数:
source-file- 源文件路径(相对于 ace_engine 根目录,或使用绝对路径)product-name- 目标产品(默认值:rk3568)--save-script- 将增强后的编译命令保存到可复用脚本文件中
工作流:
- 从 ninja 构建文件中提取编译命令
- 生成附带检测功能的增强编译命令
- (可选)将脚本保存到
out/{product}/compile_single_file_{name}.sh - 执行编译并分析时间和内存
- 解析预处理文件 .ii,以提取依赖关系
- 显示完整分析结果
使用 --save-script 时的输出:
- 在
out/{product}/compile_single_file_{name}.sh生成独立的 bash 脚本 - 脚本包含自动环境设置
- 监控性能(编译时间和峰值内存)
- 可多次执行,以便比较性能
- 可用于基准测试和验证优化效果
get_compile_command.py
从 ninja 构建系统中提取源文件的完整编译命令。
用法(在 ace_engine 根目录下):
# Display commands only
python3 ./.claude/skills/compile-analysis/scripts/get_compile_command.py \
<source-file> <openharmony_root>/out/<product>
# Save enhanced command (with performance monitoring)
python3 ./.claude/skills/compile-analysis/scripts/get_compile_command.py \
<source-file> <openharmony_root>/out/<product> --save-enhanced
示例:
# From ace_engine directory
python3 ./.claude/skills/compile-analysis/scripts/get_compile_command.py \
frameworks/core/components_ng/base/frame_node.cpp \
/home/sunfei/workspace/openHarmony/out/rk3568 --save-enhanced
功能:
- 解析 ninja 构建文件以定位编译规则
- 提取编译器标志、定义和包含路径
- 生成两个版本:
- 原始命令(开发时使用 ccache)
- 增强命令(不使用 ccache,并使用
-save-temps进行分析)
- 可将命令保存为独立脚本,以便重复执行
输出:
- 原始编译命令
- 带插桩的增强编译命令
- 可选:保存的脚本文件,供重复使用
--save:创建{file}_compile_command.sh(原始命令)--save-enhanced:创建compile_single_file_{file}.sh(包含监控功能的增强命令)
parse_ii.py
分析 .ii 预处理文件,提取并显示头文件依赖项。
用法:
python3 ./.claude/skills/compile-analysis/scripts/parse_ii.py <ii-file>
功能:
- 解析 .ii 文件(预处理后的 C++ 源代码)
- 提取指向
foundation/arkui/的#include指令 - 构建依赖树结构
- 使用 Unicode 方框绘制字符显示树
输出格式:
头文件的依赖关系树:
└── foundation/arkui/ace_engine/frameworks/core/components_ng/base/frame_node.h
└── foundation/arkui/ace_engine/frameworks/core/components_ng/base/ui_node.h
├── foundation/arkui/ace_engine/frameworks/core/pipeline/base/element.h
└── ...
理解结果
编译时间
格式:MM:SS.mm(分钟:秒.毫秒)
- 快:< 5 秒(小文件的典型耗时)
- 中等:5-15 秒
- 慢:> 15 秒(可能存在优化空间)
峰值内存
以千字节(KB)为单位报告
- 典型:100,000 - 500,000 KB(100-500 MB)
- 较高:> 500,000 KB,可能表示模板实例化或头文件依赖过多
依赖树
此树显示分层的包含关系:
- 每一层代表一条
#include指令 - 多个子节点表示文件中包含了多个头文件
- 树较深表示依赖链较长
优化指标:
- 宽树(许多直接包含)——考虑合并头文件
- 深树(链条较长)——检查循环依赖或过多的转发
- 重复路径——可能缺少头文件保护,或包含顺序存在问题
常见用例
分析头文件依赖
当需要分析源文件的头文件依赖结构时:
重要:此工作流仅使用编译脚本生成的 .ii 文件。不使用其他依赖分析方法。
工作流:
- 检查
out/{product}/obj/目录中是否存在.ii文件 - 如果存在
.ii文件 → 使用parse_ii.py直接解析 - 如果不存在
.ii文件 → 使用编译脚本生成,然后解析 - 始终将依赖树保存到
out/{product}/{file_name}_dependency_tree.txt
使用 Claude 的示例:
# User request: "分析 frame_node.cpp 的头文件依赖"
# Claude's response:
# Step 1: Check for existing .ii file
# ✓ Found: out/rk3568/obj/.../frame_node.ii
# Step 2: Parse .ii file and save dependency tree
python3 ./.claude/skills/compile-analysis/scripts/parse_ii.py \
out/rk3568/obj/.../frame_node.ii \
--output out/rk3568/frame_node_dependency_tree.txt
# Output:
# 头文件的依赖关系树:
# └── foundation/arkui/ace_engine/frameworks/core/components_ng/base/frame_node.h
# ├── foundation/arkui/ace_engine/frameworks/core/components_ng/base/ui_node.h
# │ ├── foundation/arkui/ace_engine/frameworks/core/pipeline/base/element.h
# │ └── foundation/arkui/ace_engine/base/memory/ace_type.h
# └── foundation/arkui/ace_engine/frameworks/core/components_ng/property/property.h
#
# ✓ 依赖树已保存到: out/rk3568/frame_node_dependency_tree.txt
如果 .ii 文件不存在:
# User request: "这个文件依赖了多少头文件 text_theme.cpp"
# Claude's response:
# Step 1: Check for existing .ii file
# ✗ .ii file not found
# Step 2: Check for compilation script
# ✓ Found: out/rk3568/compile_single_file_text_theme.sh
# Step 3: Generate .ii file by running compilation script
cd out/rk3568
bash compile_single_file_text_theme.sh
# Step 4: Parse .ii file and save dependency tree
python3 ../../.claude/skills/compile-analysis/scripts/parse_ii.py \
obj/.../text_theme.ii \
--output text_theme_dependency_tree.txt
# Output:
# 头文件的依赖关系树:
# └── foundation/arkui/ace_engine/frameworks/core/components/text/text_theme.h
# ├── ...
#
# ✓ 依赖树已保存到: out/rk3568/text_theme_dependency_tree.txt
#
# 统计信息:
# - 总计依赖: 47 个头文件
# - 最大深度: 6 层
如果 .ii 和脚本都不存在:
# User request: "头文件依赖关系 button_pattern.cpp"
# Claude's response:
# Step 1: Check for existing .ii file
# ✗ .ii file not found
# Step 2: Check for compilation script
# ✗ Compilation script not found
# Step 3: Generate compilation script first
python3 ./.claude/skills/compile-analysis/scripts/get_compile_command.py \
frameworks/core/components_ng/pattern/button_pattern.cpp \
<openharmony_root>/out/rk3568 --save-enhanced
# ✓ Script generated: out/rk3568/compile_single_file_button_pattern.sh
# Step 4: Generate .ii file by running script
cd out/rk3568
bash compile_single_file_button_pattern.sh
# Step 5: Parse .ii file and save dependency tree
python3 ../../.claude/skills/compile-analysis/scripts/parse_ii.py \
obj/.../button_pattern.ii \
--output button_pattern_dependency_tree.txt
# ✓ 依赖树已保存到: out/rk3568/button_pattern_dependency_tree.txt
触发短语:
- “分析这个文件的头文件依赖”
- “头文件依赖关系”
- “这个文件依赖了多少头文件”
- “分析头文件依赖”
- “头文件依赖树”
- “有多少个头文件”
输出文件命名:
- 格式:
{file_name}_dependency_tree.txt - 位置:
out/{product}/ - 示例:
out/rk3568/frame_node_dependency_tree.txt
约束:
- ✅ 必须使用
parse_ii.py解析.ii文件 - ✅ 如有需要,必须使用编译脚本生成
.ii - ✅ 必须将依赖树保存到
out/{product}/{file_name}_dependency_tree.txt - ❌ 不要使用其他依赖分析工具(如 clang -E、gcc -M 等)
- ❌ 不要尝试手动解析依赖项
单个文件的独立编译
当需要单独编译某个文件时(用于测试、调试或验证):
重要:此工作流仅使用预先生成的编译脚本。不使用其他编译方法。
工作流:
- 检查编译脚本是否存在:
out/{product}/compile_single_file_{name}.sh - 如果脚本存在 → 直接执行
- 如果脚本不存在 → 先生成脚本,然后执行
使用 Claude 的示例:
# User request: "单独编译 frame_node.cpp"
# Claude's response:
# Step 1: Check for existing script
# ✓ Found: out/rk3568/compile_single_file_frame_node.sh
# Step 2: Execute the script
cd out/rk3568
bash compile_single_file_frame_node.sh
# Output:
# 编译时间: 0:08.23
# 峰值内存: 234567 KB
# ✓ 已生成: obj/.../frame_node.ii obj/.../frame_node.o
如果脚本不存在:
# User request: "单编 text_theme.cpp"
# Claude's response:
# Step 1: Check for existing script
# ✗ Script not found: out/rk3568/compile_single_file_text_theme.sh
# Step 2: Generate script first
python3 ./.claude/skills/compile-analysis/scripts/get_compile_command.py \
frameworks/core/components/text/text_theme.cpp <openharmony_root>/out/rk3568 --save-enhanced
# ✓ Script generated: out/rk3568/compile_single_file_text_theme.sh
# Step 3: Execute the script
cd out/rk3568
bash compile_single_file_text_theme.sh
触发短语:
- “单独编译这个文件”
- “编译单个文件”
- “单编文件”
- “独立编译文件”
- “compile single file”
- “compile individual file”
- “standalone compile”
限制:
- ✅ 必须使用现有的
compile_single_file_{name}.sh脚本 - ✅ 如果脚本不存在,必须在编译前生成脚本
- ❌ 不要直接使用 ninja、make 或其他构建工具
- ❌ 不要尝试手动执行编译命令
提取和保存编译命令
当需要提取或保存编译命令以供后续使用时:
保存带性能监控的独立脚本:
./.claude/skills/compile-analysis/scripts/analyze_compile.sh \
frameworks/core/components_ng/base/frame_node.cpp rk3568 --save-script
# Script saved to: out/rk3568/compile_single_file_frame_node.sh
# Execute later: cd out/rk3568 && bash compile_single_file_frame_node.sh
仅提取命令,不执行:
python3 ./.claude/skills/compile-analysis/scripts/get_compile_command.py \
frameworks/core/components_ng/base/frame_node.cpp \
<openharmony_root>/out/rk3568 --save-enhanced
这适用于:
- 创建可重复使用的编译脚本
- 设置性能基准测试
- 生成可复现的构建环境
- 隔离特定文件编译以进行测试
调查缓慢构建
当增量构建速度低于预期时:
- 查看构建日志时间戳,找出编译缓慢的文件
- 对缓慢文件运行分析:
./analyze_compile.sh <slow-file> - 检查依赖树的深度和广度
- 查找频繁包含的庞大头文件
优化头文件依赖
为减少不必要的重新编译:
- 分析依赖树中的常见模式
- 找出被许多文件包含的头文件
- 考虑使用前置声明代替完整包含
- 对稳定的依赖使用预编译头文件(PCH)
优化前后对比
使用已保存的脚本衡量优化效果:
-
生成基准脚本:
./analyze_compile.sh <file> rk3568 --save-script cd out/rk3568 -
运行基准测量:
bash compile_single_file_{name}.sh # Record: 编译时间: 0:15.23, 峰值内存: 456789 KB -
应用优化(减少包含、使用前置声明等)
-
运行对比测量:
bash compile_single_file_{name}.sh # Record: 编译时间: 0:08.45, 峰值内存: 234567 KB -
比较结果,量化改进效果
已保存的脚本可确保编译条件一致,从而进行公平对比。
故障排除
问题:“找不到编译规则”(Compilation rule not found)
原因:源文件路径与构建数据库不匹配 解决方案:
- 确保文件位于 ace_engine 目录结构中
- 检查文件是否曾经构建过(先运行完整构建)
- 验证路径格式:使用相对于 ace_engine 根目录的路径
问题:“找不到 .ii 文件”(.ii file not found)
原因:使用 -save-temps 编译失败,或文件未创建
解决方案:
- 检查增强的编译命令是否成功
- 确认编译器支持
-save-temps=obj标志 - 手动搜索 obj 目录:
find out/<product>/obj -name "*.ii"
问题:依赖树显示的文件很少
原因:parse_ii.py 仅筛选带有 foundation/arkui/ 前缀的路径
解决方案:
- 这是预期行为——重点分析 arkui 专用头文件
- 系统头文件会被有意排除
- 修改 parse_ii.py 中的
target_prefix,以包含其他路径
最佳实践
- 先进行完整构建:确保项目至少构建过一次
- 使用相对路径:提供相对于 ace_engine 根目录的路径
- 针对产品进行分析:如果不使用默认的 rk3568,请指定产品名称
- 比较基准测试:使用已保存的结果跟踪变化
- 关注热点路径:优先分析经常修改的文件
更多资源
参考文件
有关详细工作流和高级用法:
references/workflow.md- 全面的工作流指南references/optimization.md- 优化策略和模式
示例文件
examples/ 中的可运行示例:
examples/example-analysis.sh- 完整的分析示例examples/example-output.txt- 包含解读的示例输出
与构建系统集成
此技能与 OpenHarmony GN/Ninja 构建系统集成:
- 从
out/<product>/目录读取构建元数据 - 解析
toolchain.ninja中的编译器规则 - 从 ninja 文件中提取特定文件的编译命令
- 生成兼容插桩的分析命令
增强后的编译命令通过以下方式修改原始命令:
- 移除 ccache(以获取准确的计时数据)
- 添加
-save-temps=obj(以生成 .ii 文件) - 使用
/usr/bin/time封装(以测量资源使用情况) - 屏蔽相关警告(
-Wno-undefined-bool-conversion)
这能确保测量准确,同时保持编译兼容性。