ccls
Table of Contents
1 概述
ccls 源自 cquery,是一个 C/C++/Objective-C 语言服务器。它具有以下功能:
- 代码补全(包括函数签名和代码片段)
- 定义/引用以及其他交叉引用。
- 交叉引用扩展:
$ccls/call $ccls/inheritance $ccls/member $ccls/vars ...
- 代码格式化
- 代码层次结构:调用(调用者/被调用者)层次结构,继承(基础/派生)层次结构,成员层次结构
- 符号重命名
- 文档符号和工作区符号的近似搜索
- 悬停信息
- 诊断和代码操作(clang FixIts)
- 语义突出显示和预处理器跳过区域
- 语义导航:
$ccls/navigate
它具有代码库的全局视图,并支持许多交叉引用功能,请参阅 wiki/FAQ。 当打开第一个文件时,它会开始并行地索引整个项目(包括可能存在的子项目),而主线程可以在索引完成之前为请求提供服务。保存文件将增量更新索引。
与 cquery 相比,它利用了 C++ 17 的特性,具有较少的第三方依赖性和较小的代码库。它像 clangd 一样利用 Clang C++ API,为代码完成和诊断提供了更好的支持。Refactoring(反射?) 由 clang-include-fixer 和其他基于 Clang 的工具提供。
与 cquery 比较(截止 2018-07-15):
cquery | ccls | |
---|---|---|
third_party | more | fewer |
C++ | C++14 | C++17 |
clang API | libclang(C) | clang/llvm C++ |
Filesystem | AbsolutePath + custom routines | llvm/Support |
index | libclang | clangIndex, some enhancement |
pipeline | index merge+id remapping | simpler and more robust |
cquery 有系统头文件检测功能(通过运行编译器驱动程序),而 ccls 使用 clangDriver。
2 安装1
安装依赖环境:
docker run -it --name ccls-build ubuntu:18.04 /bin/bash apt install -y git gcc cmake clang-8 libclang-8-dev llvm-8 llvm-8-dev zlib1g-dev libncurses-dev
编译代码:
git clone --depth=1 --recursive https://github.com/MaskRay/ccls
cd ccls
cmake -H. -BRelease -DCMAKE_BUILD_TYPE=Release
cmake --build Release --target install
3 编辑器配置
我在 emacs 中使用 ccls,需要配合 emacs-ccls 一起使用。
4 项目配置2
ccls通常索引整个项目。 为了使其正常工作,ccls需要能够获取源文件列表及其编译命令行。 这有两种主要方式:
- 在项目根目录中提供
compile_commands.json
- 提供
.ccls
文件。 它是一个基于行的、描述编译器标志的文本文件。 递归列出的源文件(标题除外)将被编入索引。
如果两者都不存在,那么当ccls启动时它将不会索引任何内容:相反,它将等待 LSP 客户端打开文件并仅索引这些文件。
4.1 compile_commands.json
通常,此文件不会纳入源代码管理,而是由构建系统生成。 这意味着项目中,最好在启动 ccls 服务器之前生成它。
由于此文件是自动生成的,因此不容易自定义。 因此,可以在同一个项目中同时提供 compile_commands.json
和 .ccls
,并通过 .ccls
的配置增强 compile_commands.json
中的选项。
如果 compile_commands.json
不在项目根目录中,请将初始化选项 compilationDatabaseDirectory
设置为包含 compile_commands.json
的备用目录。
4.1.1 cmake
使用 cmake 生成该文件:
cmake -H. -BDebug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES ln -s Debug/compile_commands.json
4.2 .ccls
File
.ccls
是项目根目录下的基于行的文本文件。 它的主要功能是指定正确索引代码所需的编译器标志: -I -D
等。每行包含一个要添加到编译器命令行的参数。 不对参数执行空格分割,因此不能使用 -I foo=(例如,使用 =-Ifoo
或 -I\nfoo
)。
如果需要,项目的子目录还可以包含 .ccls
文件,以指定特定于这些目录的编译器标志。
一行可以选择以一个或多个 %
指令开头,这些指令专门用于该行的参数。
可用的指令包括:
4.2.1 %compile_commands.json
默认情况下,.ccls编译器标志仅应用于未在compile_commands.json中列出的文件。如果此指令首先出现在.ccls中,则在解析compile_commands.json之后,其余的.ccls参数将附加到compile_commands.json中找到的文件的编译器标志。
4.2.2 %c / %cpp / %objective-c / %objective-cpp
仅在解析C (%c), C++ (%cpp), Objective-C (%objective-c), or Objective-C++ (%objective-c++) 时才添加此参数。
4.2.3 %cu
只有在解析CUDA文件时才应添加此参数。如果要将选项添加到CUDA和常规C ++文件,请编写 %cpp%cu -DA
。
4.2.4 %h / %hpp
仅在索引 C header files ( %h: *.h
) or C++ header files (%hpp: *.hh *.hpp)
时才应添加此参数。注意, *.h
文件被认为是C,而不是C ++。
可以添加这些行以使每个 *.h
解析为C ++:
%h -x %h c++-header
请注意,如果您的项目同时包含C和C++ 文件,则可以从C文件中推断出a.h的标志,从而将其解析为C.您可能会遇到类似未知类型名称“class”的解析错误。
4.2.5 Compiler driver
编译器驱动程序(第一行除非使用%compile_commands.json)通常只能是clang。 clang ++通常是不必要的,如果某些文件是C则不正确。
请注意,clang a.cc和clang ++ a.cc是不同的,但区别仅在于链接(传递默认运行时库)并且与ccls执行的前端操作无关。
4.3 .ccls examples
Example A
clang %c -std=c11 %cpp -std=c++2a %h %hpp --include=Global.h -Iinc -DMACRO *.h *.hh *.hpp files will be parsed with extra --include=Global.h
Example B
%compile_commands.json %c -std=c11 %cpp -std=c++14 %c %cpp -pthread %h %hpp --include=Global.h -Iinc
它会附加标志,因此不应使用clang。
Example: -march=armv7a
See https://github.com/MaskRay/ccls/issues/107. 如果编译器驱动程序是GCC交叉编译器,则可能需要 --target
。 假设使用 arm-linux-gnueabi-gcc-march = armv7a
,添加 --target =
:
%compile_commands.json --target=armv7a-linux-gnueabi