前言
最近的新工作是第一次在Mac上对进行Chrome的二次开发。作为一个VSCode爱好者,必须在VSCode上搭建一个用着顺手的开发环境。
Chrome使用了GN/Ninja作为构建系统,llvm/clang作为编译器。由于编辑过程比较复杂,自带的C/C++插件无法做到开箱即用,恰好llvm项目有一个clangd的子项目,提供语法分析的服务,而clangd恰好有VSCode的插件,而Chrome也很贴心地提供了clangd所需的compile_commands.json
的生成脚本。
这个方案看起来很美好,但是在实际使用中,发现了一些问题:
- clangd有了
compile_commands.json
之后,除了会解析当前正在编辑的文件及其依赖,还会自动去解析项目中所有的文件,这个过程会非常耗时(大约七八个小时),这个过程还会占用大量的CPU资源,导致电脑风扇狂转,让本就散热捉急的MBP2019变得更加烫手。 - 分析完所有文件后,如果代码有大批量的更改,比如切换分支,对main分支进行rebase等等,clangd会自动重新分析,main分支一天的commit的代码更改,便会导致clangd对几乎所有的文件进行重新分析。
针对这个问题,clangd是有一个解决方案的,那就是clangd indexer server。只需要在本地生成一次clangd index文件,然后使用clangd index server加载,就组成了一台可以供多个客户端使用的clangd indexer server。这样就可以避免每次都要重新生成clangd index文件,而且可以在多个客户端共享。
虽然Chrome很复杂,但是Chrome也是可以搭建clangd index server的,Chrome官方就有也有自己的clangd index server。作为Chrome的二次开发者,我们是不能直接用Chrome的index server的,所以我们需要搭建自己的clangd index server。
一些挑战
- Chrome使用的llvm版本并不是release版本,而是Chrome自己内部编译的版本,而我们的Chrome也使用了我们自己内部定制编译的llvm,而这个定制版本的llvm是不包含clangd的,所以我们需要自己编译clangd。
- Chrome官方的clangd index server是针对Linux的,搜索了网上的内容,Mac版本的Chrome remote index并没有人分享过相关内容,需要自己蹚水。
准备工作
- 确保本地已经安装好了Chrome的编译环境,即已经编译过一次Chrome
- 安装cmake,git,ninja,brew
搭建步骤
确定clangd的版本和gRPC的版本,并且下载其源码
- 在src目录下执行
gclient sync
在shell中运行
third_party/llvm-build/Release+Asserts/bin/clang --version
你会得到类似于以下的信息clang version 15.0.0 (https://github.com/llvm/llvm-project.git 4ba6a9c9f65bbc8bd06e3652cb20fd4dfc846137) Target: x86_64-apple-darwin21.6.0 Thread model: posix InstalledDir: /Users/xc/repos/llvm-project/build/bin
其中的
4ba6a9c
就是llvm的commit version- 下载llvm源码,执行
git clone https://github.com/llvm/llvm-project
- 切换到llvm的commit version,执行
git checkout 4ba6a9c
(将4ba6a9c替换为你自己的commit version) - 在llvm的clang-tools-extra/clangd/index/remote/README.md文件中,写有grpc的版本号,以及代码的下载方式(本文以v1.36.3为例)
- 下载grpc源码,执行
git clone -b v1.36.3 https://github.com/grpc/grpc
编译gRPC(作为clangd的依赖项)
在上一步中的README.md中,有编译gRPC的步骤,如果已经按照步骤编译过gRPC,可以跳过这一步。PS:以下命令都是在grpc的根目录下执行1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25# 使用brew安装编译gRPC所需的依赖
brew install autoconf automake libtool shtool
# 加载git submodule中的内容
git submodule update --init
mkdir build
# 下一步中我们会用GRPC_INSTALL_PATH来指定gRPC的安装路径,这里我们指定为~/.grpc_install
export GRPC_INSTALL_PATH=$HOME/.grpc_install
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \ # Release模式
-DgRPC_INSTALL=ON \
-DgRPC_BUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=$GRPC_INSTALL_PATH \
-G Ninja
# CMAKE_BUILD_TYPE=Release选项开启Release模式,gRPC的性能会更好
# gRPC_INSTALL=ON选项可以在编译后对gRPC进行安装,
# gRPC_BUILD_TESTS=OFF选项可以避免编译gRPC的测试用例
# CMAKE_INSTALL_PREFIX=$GRPC_INSTALL_PATH 选项指定gRPC的安装路径
# -G Ninja选项可以使用ninja来编译gRPC
# 编译gRPC,并且安装到~/.grpc_install目录下
cmake --build build --target install
编译clangd
使用shell进入llvm的根目录,执行以下命令1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17makedir build
# 使用上一步中的GRPC_INSTALL_PATH来指定gRPC的安装路径
export GRPC_INSTALL_PATH=$HOME/.grpc_install
cmake -S llvm -B build \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
-DCLANGD_ENABLE_REMOTE=On \
-DCMAKE_INSTALL_PREFIX=$GRPC_INSTALL_PATH \
-DGRPC_INSTALL_PATH=$GRPC_INSTALL_PATH \
-G Ninja
# -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" llvm默认只编译clang,这里我们需要编译clangd,所以需要加上clang-tools-extra
# -DCLANGD_ENABLE_REMOTE=On 开启clangd的remote模式(默认是关闭的)
# -DCMAKE_INSTALL_PREFIX=$GRPC_INSTALL_PATH 指定gRPC的安装路径
cmake --build build
生成compile_commands.json
生成ninja build的中间文件
生成clangd的remote index
TODO:未完待续…
中间遇到的坑
版本不匹配
clangd和gRPC的版本不匹配,会导致编译失败。
我因为这个原因,编译了好几次,最终才摸索出找到正确的匹配的版本号的方法中间文件缺失
后记
…