用 VS Code 写 OpenHarmony 代码时,经常会遇到智能提示极慢,比如跳转函数定义和实现要卡很久。

在中文互联网上基本搜不到直接的解答,参考社区文章以及 GitHub 和 Reddit 上的讨论,终于找到了根本原因和解决方案。

相关讨论链接:


为什么会卡

其实就是微软官方的 C/C++ 扩展在大型工程下的索引机制问题:

微软官方 C/C++ 扩展插件

这个插件每次打开工程都会自动递归扫描所有头文件路径来建索引。对于小项目很方便,但 OpenHarmony 源码超过 20GB、包含几十万个文件,全量扫描会直接把磁盘 I/O 和 CPU 吃满,导致跳转时卡死。


第一步:生成编译数据库

解决卡顿的核心,就是给开发工具提供一个精准的 compile_commands.json(编译数据库)。

什么是 compile_commands.json

它记录了工程里每个源文件真实的编译命令、宏定义和头文件包含路径。有了它,插件直接按真实指令分析代码,不需要再无脑扫描整个 20GB 的源码目录。

它长这样:

1
2
3
4
5
6
7
8
[
{
"directory": "/home/xxx/workspace/OpenHarmony-v3.1-Release/out/hispark_pegasus/wifiiot_hispark_pegasus",
"command": "ccache riscv32-unknown-elf-gcc -D_XOPEN_SOURCE=700 -DOHOS_DEBUG -D__LITEOS__ -D__LITEOS_M__ -I../../../applications/sample/wifi-iot/app/loc_info_collector/gpsM_uart -I../../../kernel/liteos_m/components/cmsis/2.0 -c ../../../applications/sample/wifi-iot/app/loc_info_collector/mqtt/wb_ram.c -o obj/applications/sample/wifi-iot/app/loc_info_collector/mqtt/libmain_process.wb_ram.o",
"file": "../../../applications/sample/wifi-iot/app/loc_info_collector/mqtt/wb_ram.c",
"output": "obj/applications/sample/wifi-iot/app/loc_info_collector/mqtt/libmain_process.wb_ram.o"
}
]

生成步骤

  1. 进入 build.ninja 所在的目标构建目录:
    1
    cd out/hispark_pegasus/wifiiot_hispark_pegasus/

Ninja 构建文件所在目录

  1. 通过 ninja 的 compdb 工具导出编译数据库:

    1
    ninja -C ./ -t compdb cxx cc > compile_commands.json

    注:该命令本质上是将 ninja -C ./ -t compdb cxx cc 导出的编译信息重定向到 compile_commands.json 文件中。

  2. 将生成的 compile_commands.json 移动到 OpenHarmony 源码根目录下:

    1
    mv ./compile_commands.json ../../../
  3. 编写自动化一键脚本(可选):
    在修改 OpenHarmony 模块结构或增删源文件时,compile_commands.json 需要重新生成。可将上述步骤封装为 Bash 脚本:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

workspace=~/workspace/OpenHarmony-v3.1-Release/
build_dir=$workspace/out/hispark_pegasus/wifiiot_hispark_pegasus/

cd $build_dir

# 1. 导出编译数据库
ninja -C $build_dir -t compdb cxx cc > compile_commands.json

# 2. 移动到源码根目录
mv compile_commands.json $workspace

方案一:继续使用微软官方插件

如果不想换插件,可以直接配置 .vscode/c_cpp_properties.json,让它读取编译数据库,不再自己扫描头文件:

1
2
3
4
5
6
7
8
9
10
{
"configurations": [
{
"name": "OpenHarmony",
// 指定编译数据库路径,避免全局递归扫描
"compileCommands": "${workspaceFolder}/compile_commands.json"
}
],
"version": 4
}

配置后插件直接通过编译数据库找头文件和宏定义,不会再在后台狂扫 20GB 源码,跳转速度会明显提升。


方案二:切换到 Clangd

想要更极致的秒级跳转和更低的内存占用,推荐切换到 Clangd。

1. 本地安装后端

VS Code 的 clangd 插件只是客户端,电脑本地需要先安装好后端程序:

  • 官方预编译安装包:前往 Clangd Releases 页面 下载对应系统的压缩包(解压后将 bin/clangd 路径加入系统环境变量 PATH 即可)。
  • 通过包管理器安装
    • Ubuntu / Debian
      1
      2
      # 安装 clangd 服务端
      sudo apt update && sudo apt install clangd
    • macOS
      1
      2
      # 使用 Homebrew 安装
      brew install llvm
    • Windows
      1
      2
      # 使用 winget 安装,或者直接下载官方 zip 解压
      winget install LLVM.LLVM

2. 插件搭配推荐

Clangd 只负责代码分析,不带格式化和调试功能,建议按下面这套搭配:

  1. clangd:负责代码补全、语法高亮和函数跳转。
  2. Clang-Format:负责代码格式化(style 可设为 "WebKit")。
  3. CodeLLDB:负责 C/C++ 断点调试。

VS Code clangd 语言服务插件

Clang-Format 代码格式化插件

3. 过滤 GCC 专有参数

OpenHarmony 的编译命令里有一些 GCC/RISC-V 专用参数,Clangd 可能会报无法识别的警告。有两种解决方式:

方式 A:使用 .clangd 配置文件

在 OpenHarmony 源码根目录下创建 .clangd 配置文件,clangd 会在索引时自动过滤这些不支持的参数:

1
2
3
4
5
6
7
8
9
# 在工程根目录下创建 .clangd
CompileFlags:
# 过滤 Clangd 无法识别的 GCC / RISC-V 专有编译选项
Remove:
- -fno-optimize-strlen
- -freorder-blocks-algorithm=simple
- -mno-small-data-limit=0
- -fno-aggressive-loop-optimizations
- -msave-restore

方式 B:脚本清洗

也可以在导出 compile_commands.json 文件时用 sed 顺手把不兼容参数删掉:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

workspace=~/workspace/OpenHarmony-v3.1-Release/
build_dir=$workspace/out/hispark_pegasus/wifiiot_hispark_pegasus/

cd $build_dir

# 1. 导出编译数据库
ninja -C $build_dir -t compdb cxx cc > compile_commands.json

# 2. 清洗 GCC 专有参数
sed -i 's/-fno-optimize-strlen//g' compile_commands.json
sed -i 's/-freorder-blocks-algorithm=simple//g' compile_commands.json
sed -i 's/-mno-small-data-limit=0//g' compile_commands.json
sed -i 's/-fno-aggressive-loop-optimizations//g' compile_commands.json
sed -i 's/ / /g' compile_commands.json

# 3. 移动到工程根目录
mv compile_commands.json $workspace

4. 检查生效

打开 VS Code,看底部状态栏的 clangd: idle,只要在转圈说明正在建索引。如果没反应,按 Ctrl + Shift + P 执行 clangd: Restart language server 重启即可。

VS Code 底部状态栏 clangd 运行状态