前言

最近使用 C/C++ 开发,在 Emacs 下使用 Cmake 作为编译工具,结合 ccls 进行代码补全,有着不错的体验,于是记录一下。

ccls 介绍

ccls 是基于cqueryC/C++/Objective-C 的代码补全的工具,它实现了 C/C++/Objective-CLanguage Server Protocol的服务端。支持代码补全,代码的引用查找和跳转,有着良好的体验。

我使用 ccls 是由于它能支持 lsp ,可以在 Emacs 中使用。当然也是支持 AtomVimVSCode 等编辑器的。

安装ccls

Mac

mac 下安装 ccls 使用 brew install ccls 十分的方便,但是这个版本还停留在 0.20190823.6 实在是太老旧了。使用过程中发现并不能很好的工作,建议采用源码编译。

编译过程如下

cmake &llvm

ccls 的编译需要 cmakellvm ,所以在编译之前需要安装 cmakellvm

1
brew install cmake llvm

使用 brew 安装的 llvm 路径在 /usr/local/Cellar/llvm/10.0.1 ,编译 ccls 会用到。

编译ccls

1
2
3
4
git clone --depth=1 --recursive https://github.com/MaskRay/ccls
cd ccls
cmake -H. -BRelease -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/10.0.1/lib/cmake -DUSE_SYSTEM_RAPIDJSON=off
cmake --build Release --target install

ccls 会被安装到 /usr/local/bin/ccls

其中 -DCMAKE_PREFIX_PATH 需要换成你的 llvm 的安装路径。

这样 ccls 就编译好了。

Linux

我所使用的 Linux 发行版是 Manjaro ,所以安装起来就非常方便了。

1
sudo pacman -S ccls-git

命令执行完,也就安装好了,非常省事。

其它 Linux 发现版,可以参考 Build · MaskRay/ccls Wiki

为项目配置 ccls 补全

当我们装好 ccls 后,就可以使用 Emacs 结合 lsp 打开 C/C++ 的项目,在项目的根目录下就会生成 .ccls-cache 的文件夹。这就表示当前项目被 ccls 识别了。

做完上面之后,我们打开文件,会发现许多文件都会找不到头文件,补全也不完整,甚至连 iostream 都找不到,这就很纳闷了。

我的 C/C++ 项目采用的是 cmake 作为编译工具,所以在查找官网资料后,发现只要在使用 cmake 的时候加上 -DCMAKE_EXPORT_COMPILE_COMMANDS=On ,然后把 compile_commands.json 放到根目录就行。 具体操作入下

1
2
3
4
mkdir build && cd build
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=On ..
cd ..
ln -s build/compile_commands.json

-DCMAKE_EXPORT_COMPILE_COMMANDS 会告诉 cmake 把编译的指令都导出到 compile_commands.json 中,当 ccls 解析 compile_commands.json 后就知道源码在哪里了,知道去哪里找头文件等等。

除了在命令行加上 -DCMAKE_EXPORT_COMPILE_COMMANDS 参数外,还可以在 cmake 中设置,这样就可以避免每次编译都要输入,或者忘记。

1
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

如果你不是使用 cmake 作为编译工具可以参考 Project Setup · MaskRay/ccls Wiki

在 QT 中使用 ccls

在上面提到过,要为项目配置 ccls 关键就是 compile_commands.json ,所以想要在 QT 中使用 ccls 就需要生成 compile_commands.json 文件。

QtCreate 的菜单栏中,选择构建 -> Generate Complation Database for xxx 就会在编译的目录(Build directory,可以项目的构建设置中查看)下生成 compile_commands.json 文件。

最后把 compile_commands.json 软连接到项目的根目录,这样就能够使用 ccls 来补全代码了。

更新ccls

随着时间的流逝,我们的软件包在不断的更新,这时候就会碰到,我们的程序明明是对的,但是还是报错,就连最基本的 std::cout 都报错,这时候就需要考虑是不是升级了 llvm

如果你升级了 llvm 那么你是需要重新编译一下 ccls ,因为 llvm 的路径变了,所以查找的路径也跟着变了。

这时候我们只需要照着上面的步骤再执行一遍就可以了。别忘记编译参数 DCMAKE_PREFIX_PATH 要更新。

更新完之后就可以正常使用了。

错误 c++ is not able to compile a simple test program

1
2
3
4
5
6
CMake Error at /usr/local/Cellar/cmake/3.21.1/share/cmake/Modules/CMakeTestCXXCompiler.cmake:62 (message):
  The C++ compiler

    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++"

  is not able to compile a simple test program.

碰到这个问题的解决办法是需要删除掉 Release 目录,就能正常编译。

1
2
cd ccls
rm -rf Release

参考