mcpField
C
compile-analysis

compile-analysis

github.com/openharmonyinsight开发3596 次安装11 周前更新
代码仓库

关于 compile-analysis

面向 ACE Engine 开发者的编译分析技能,可测量单个源文件的编译耗时和峰值内存,并解析头文件依赖树。结果基于实际编译执行,支持保存脚本以便重复测试。

主要功能

  1. 01测量单文件编译时间与峰值内存
  2. 02从 ninja 构建文件提取编译命令
  3. 03解析并显示头文件依赖树
  4. 04生成可重复执行的编译脚本

适用场景

  1. 01定位编译耗时较长的源文件
  2. 02检查源文件的头文件依赖
  3. 03重复运行单文件编译以比较性能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/openharmonyinsight/openharmony-skills --skill compile-analysis

安装后在 Claude Code 中输入/compile-analysis确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
examples/
example-workflow.md
references/
optimization.md
workflow.md
scripts/
analyze_compile.sh
get_compile_command.py
parse_ii.py

详细介绍

编译效率分析技能

分析 ACE Engine 项目中单个源文件的编译效率。此技能可详细展示编译时间、资源开销和头文件依赖关系,帮助发现优化机会。

概述

编译分析通过测量以下指标,帮助识别构建过程中的性能瓶颈:

  • 编译时间 - 编译一个文件所需的时间
  • 资源开销 - 编译期间的峰值内存用量
  • 头文件依赖 - 所包含头文件的树形结构

关键要求:

  • ⚠️ 可在当前项目目录中执行 analyze_compile.sh 脚本
  • ⚠️ 必须在 out/{product} 目录中执行提取的编译命令(不能从项目根目录执行)
  • ⚠️ 所有分析结果必须基于实际执行,不得猜测或估算
  • ⚠️ 必须使用内置的 parse_ii.py 脚本解析头文件依赖并分析 .ii 文件——不得使用其他方法

在以下情况下使用此分析:

  • 调查编译缓慢的问题
  • 找出依赖过多的文件
  • 优化构建性能
  • 了解包含关系

分析工作流

步骤 1:定位源文件

确定要分析的目标源文件。ace_engine 中的源文件通常遵循以下路径格式:

  • frameworks/core/components_ng/base/frame_node.cpp
  • frameworks/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:解读结果

分析会生成三个关键输出:

  1. 编译命令 - 包含所有标志的完整编译器命令
  2. 性能指标:
    • 耗时(格式:MM:SS.mm)
    • 峰值内存用量,单位为 KB
  3. 依赖树 - 以层级结构展示头文件的包含关系

使用 --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 - 将增强后的编译命令保存到可复用脚本文件中

工作流:

  1. 从 ninja 构建文件中提取编译命令
  2. 生成附带检测功能的增强编译命令
  3. (可选)将脚本保存到 out/{product}/compile_single_file_{name}.sh
  4. 执行编译并分析时间和内存
  5. 解析预处理文件 .ii,以提取依赖关系
  6. 显示完整分析结果

使用 --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 构建文件以定位编译规则
  • 提取编译器标志、定义和包含路径
  • 生成两个版本:
    1. 原始命令(开发时使用 ccache)
    2. 增强命令(不使用 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 文件。不使用其他依赖分析方法。

工作流:

  1. 检查 out/{product}/obj/ 目录中是否存在 .ii 文件
  2. 如果存在 .ii 文件 → 使用 parse_ii.py 直接解析
  3. 如果不存在 .ii 文件 → 使用编译脚本生成,然后解析
  4. 始终将依赖树保存到 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 等)
  • ❌ 不要尝试手动解析依赖项
单个文件的独立编译

当需要单独编译某个文件时(用于测试、调试或验证):

重要:此工作流仅使用预先生成的编译脚本。不使用其他编译方法。

工作流:

  1. 检查编译脚本是否存在:out/{product}/compile_single_file_{name}.sh
  2. 如果脚本存在 → 直接执行
  3. 如果脚本不存在 → 先生成脚本,然后执行

使用 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

这适用于:

  • 创建可重复使用的编译脚本
  • 设置性能基准测试
  • 生成可复现的构建环境
  • 隔离特定文件编译以进行测试
调查缓慢构建

当增量构建速度低于预期时:

  1. 查看构建日志时间戳,找出编译缓慢的文件
  2. 对缓慢文件运行分析:./analyze_compile.sh <slow-file>
  3. 检查依赖树的深度和广度
  4. 查找频繁包含的庞大头文件
优化头文件依赖

为减少不必要的重新编译:

  1. 分析依赖树中的常见模式
  2. 找出被许多文件包含的头文件
  3. 考虑使用前置声明代替完整包含
  4. 对稳定的依赖使用预编译头文件(PCH)
优化前后对比

使用已保存的脚本衡量优化效果:

  1. 生成基准脚本:

    ./analyze_compile.sh <file> rk3568 --save-script
    cd out/rk3568
    
  2. 运行基准测量:

    bash compile_single_file_{name}.sh
    # Record: 编译时间: 0:15.23, 峰值内存: 456789 KB
    
  3. 应用优化(减少包含、使用前置声明等)

  4. 运行对比测量:

    bash compile_single_file_{name}.sh
    # Record: 编译时间: 0:08.45, 峰值内存: 234567 KB
    
  5. 比较结果,量化改进效果

已保存的脚本可确保编译条件一致,从而进行公平对比。

故障排除

问题:“找不到编译规则”(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 文件中提取特定文件的编译命令
  • 生成兼容插桩的分析命令

增强后的编译命令通过以下方式修改原始命令:

  1. 移除 ccache(以获取准确的计时数据)
  2. 添加 -save-temps=obj(以生成 .ii 文件)
  3. 使用 /usr/bin/time 封装(以测量资源使用情况)
  4. 屏蔽相关警告(-Wno-undefined-bool-conversion)

这能确保测量准确,同时保持编译兼容性。

评论

支持 Markdown