Emacs 使用 irony-mode 进行代码补全

2018-12-17

介绍

Emacs 搭建 C/C++ 开发环境时如何配置代码补全呢?我选择使用 irony-mode,它是一个 C/C++ 的 minor mode,作用是代码补全。其内部基于 libclang 实现。在本文中,我将介绍 irony-mode 的配置方法。

libclang

irony-mode 基于 libclang,libclang 是什么呢?它的主页在这里

其介绍为:

The C Interface to Clang provides a relatively small API that exposes facilities for parsing source code into an abstract syntax tree (AST), loading already-parsed ASTs, traversing the AST, associating physical source locations with elements within the AST, and other facilities that support Clang-based development tools.

C/C++ 语言的 C 接口,提供了一个相对较小的 API,暴露特性包括:将源代码解析为抽象语法树(AST),加载已经解析出来的 AST,遍历 AST,将物理位置与 AST 对应位置建立关联,以及其它支持基于 C/C++ 语言开发工具的功能。

irony-server

irony-mode 采用 C/S 架构,C 部分作为 Emacs 的 Irony Mode,在运行时调用 irony-server。

irony-server 由 C++ 编写实现,它是对 libclang 的一层封装,向 Irony Mode 提供可调用的接口。文档中说,irony-server 使用了一种基于 S 表达式的简单协议,来实现代码补全。

TODO:代码补全的原理具体是如何实现的呢?后续有时间再研究下。

irony-server 从 melpa 下载下来时是源代码的形式,需要在本机进行编译,因此需要本机满足依赖:CMake(>= 2.8.3) 和 libclang。

安装与设置

安装参考项目首页。需要指出的是在 macOS 下的安装过程要麻烦一些。主要问题出在用于编译 irony-server 的 LLVM,在 macOS 下好像 libclang 有点问题。

macOS LLVM 的解决方法可以参考这篇 wiki

下面给出我的设置,我使用了 use-package 来管理依赖:

(use-package irony
  :defer t
  :diminish irony-mode
  :init
  (add-hook 'c++-mode-hook 'irony-mode-when-supported)
  (add-hook 'c-mode-hook 'irony-mode-when-supported)
  :config
  (irony-cdb-autosetup-compile-options))

Company 补全

如果你使用 Company 进行代码补全,为了能让 irony-mode 与 Company 衔接起来,需要安装包 company-irony

具体安装方式参考官方文档,我的具体设置将在下一节中一起给出。

头文件补全

irony-mode 美中不足的一点在于它无法补全头文件。有一个包 company-irony-c-headers 弥补了这一问题。

具体安装方式参考官方文档,需要注意的是,在向 company-backend 添加 backend 的时候,company-irony-c-headers 要在 company-irony 之前添加。

最终,我的 Company 的设置为:

(use-package company-irony-c-headers
  :after irony)

(use-package company-irony
  :after (irony company-irony-c-headers)
  :config
  (add-to-list 'company-backends '(company-irony-c-headers company-irony)))

使用效果

下面通过几张图来展示下 irony-mode 的使用效果。

① 头文件补全

其中:

  • 成功识别出了系统中的头文件

② 方法补全

其中:

  • 方法名称与参数类型都展示地非常完整