最強のC/C++インデクサー "Rtags" を本気で使う


関数定義や参照へキーひとつで飛ぶことのできるタグジャンプ。いまやコードリーディングに無くてはならない機能ですが、これを可能にするのがCtagsやGNU GLOBAL (Gtags) といった「インデクサー」です。
本記事では、C/C++用の優れたインデクサーである[Rtags](https://github.com/Andersbakken/rtags)のセットアップの方法、そしてVimとの連携の仕方について書いていきます。

## **Rtagsの利点**

インデクサーは、ソースコードをパースして関数や変数などのシンボル名と位置を記録したタグ（インデックス）データベースを作成するプログラムです。
Ctagsは現在最も広く使われているインデクサーの一つで、Cを始めとしてRubyやPythonなど、40あまりの言語に対応しています。ところがC++では文法の複雑さゆえに内部のパーサーが十分に対応できず、正しくシンボル名を認識できなかったりします。Gtagsも同様の問題を抱えています。
そこで最近登場したのが[Rtags](https://github.com/Andersbakken/rtags)です。RtagsはC/C++コンパイラであるclangの構文解析インターフェースを利用しているのが特徴です。コンパイラがソースコードのパースをやるわけですからミスは起こりえませんし、非常に合理的です。

## **Rtagsのインストール**

インストール自体はビルドが必要なだけで、特に難しくはありません。

### **必要なパッケージ**

* libclang >= 3.2 （3.5以上推奨）
* GCC >=4.7 もしくは clang >= 3.2
* CMake >= 2.8

私のUbuntu-14.04では下記のコマンドで入りました。llvm-configでlibclangのバージョンを調べると、3.4であることが分かります。

```console
$ sudo apt-get install clang libclang-dev cmake
$ llvm-config --version
3.4
```

このままでも問題ありませんが、libclangは3.5以上推奨とありますので、3.6を入れてみるのも良いでしょう。

```console
$ sudo apt-get install libclang-3.6-dev
$ /usr/lib/llvm-3.6/bin/llvm-config --version
3.6
```

この場合はあとでcmakeを行う際に、下記のように`LIBCLANG_LLVM_CONFIG_EXECUTABLE`に3.6のllvm-configのパスを与えて実行する必要があります。これを忘れるとデフォルトの3.4が使われてしまいます。

```console
$ LIBCLANG_LLVM_CONFIG_EXECUTABLE=/usr/lib/llvm-3.6/bin/llvm-config cmake ..
```

### **ビルド**

レポジトリをクローンして、依存するサブモジュールを更新します。

```console
$ git clone https://github.com/Andersbakken/rtags
$ cd rtags
$ git submodule init
$ git submodule update
```

cmakeでMakefileを生成しビルドします。buildディレクトリを作ってそこからout-of-sourceビルドします。

```console
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
```

out-of-sourceビルドって何？という方は[こちらの記事](http://qiita.com/osamu0329/items/7de2b190df3cfb4ad0ca)が詳しいです。

## **Rtagsのセットアップ**

インストールが完了すると、`rc`と`rdm`とというコマンドが使えるようになっているはずです。Rtagsはクライアント・サーバー型のタグシステムで、以下がインデクシングのおおまかな流れになります。

1. `rdm`を起動
2. **`rc`でインデクシング対象ソースファイルのコンパイルコマンドを与える**
3. `rdm`が`rc`から上記のコマンドを受け取り、インデクシングを行う

rcにコンパイルコマンドを与える方法が一番の肝です。おおまかに2種類の方法があります。

1. `rc -c`コマンドで直接渡す
    * 1-1. 直接手打ち
    * 1-2. ラッパースクリプトを使う
2. `rc -J`コマンドでcompile_commands.jsonファイルで渡す
    * 2-1. cmake / ninjaを使う
    * 2-2. **bearを使う ★オススメ！**

### **方法1: `rc -c`コマンドで直接渡す**

対象となるソースファイルのコンパイルコマンドを、下記のように`rc`に直接渡します。

```console
$ rc -c g++ a.cpp b.cpp
```

数個のソースファイルならこれでも良いですが、大抵の場合は毎回このようにコマンドを打つのは苦痛です。そこで、作者が用意しているラッパースクリプトを使用する方法があります。以下のようにするのがおすすめです。

```
## 自分のホームディレクトリにbinディレクトリを作成
$ mkdir ~/bin

## サーチパスの先頭におく
$ echo 'export PATH=${HOME}/bin:${PATH}' >> .bashrc

## ラッパースクリプトをコピー
$ cp rtags/bin/gcc-rtags-wrapper.sh ~/bin/gcc
$ cp rtags/bin/gcc-rtags-wrapper.sh ~/bin/g++
```

このようにすると、gcc, g++コマンドを打つたびに実際にはこのラッパースクリプトが呼ばれ、内部で`rc -c`を実行してくれます。コンパイルのたびにインデクシングが行われて大変便利です。もちろんgcc, g++の動作に影響は与えません。


### **方法2: `rc -J`コマンドでcompile_commands.jsonを読み込ませる**

compile_commands.jsonは、JSON Compilation Databaseというもので、コンパイルに必要な情報を記録したJSONファイルです。このファイルを`rc`に読み込ませることでインデクシングを行うことができます

cmakeやninjaといった最近のビルドシステムはビルド時にJSON Compilation Databaseを出力することができますので、下記のようにすればOKです。

```
## cmakeを使う場合
$ cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=1
$ rc -J .

## ninjaを使う場合
$ ninja -t commands | rc -c -
```

小規模なプロジェクトでGNU Makeしか使っていないような場合は、[Bear](https://github.com/rizsotto/Bear)というツールの助けを借りることでCompilation Databaseを出力することができます。このやり方が個人的には最もオススメです。
下記のようにビルド＆インストールします。

```console
$ git clone https://github.com/rizsotto/Bear
$ cd Bear
$ mkdir build && cd build
$ cmake ..
$ make && sudo make install
```

使い方は簡単で、通常のmakeコマンドの前にbearと打つだけです。これでMakefileより呼ばれたコンパイルコマンドをもとにCompilation Databaseが出力されます。

```console
$ bear make
$ rc -J .
```


## **RtagsをVimから使う**

[vim-rtags](https://github.com/lyuts/vim-rtags)というプラグインがあります。まだ開発中とのことですが、現時点でも十分な機能を備えています。

### **インストール・設定**

Python拡張を使用していますので+pythonが必須です。NeoBundleで簡単に入ります。

```vim
NeoBundle 'lyuts/vim-rtags'
```

デフォルトのキーマップはストローク数が多くてちょっと打ちづらいです。plugin/rtags.vimにマッピングを行っている箇所があるので、これを参考にして別のキーに割り当てると良いでしょう。私は下記のように設定しています。

```vim
" 定義へジャンプ
nnoremap <silent> <F3> :call rtags#JumpTo()<CR>
" 参照へジャンプ
nnoremap <silent> <F4> :<C-u>Unite<Space>rtags/references<CR>
" クラス・関数定義内にいたらその先頭へジャンプ
nnoremap <silent> <F5> :call rtags#JumpToParent()<CR>
```

### **使い方**

すでにcompile_commands.jsonを出力し、`rc -J .`を一度は実行させているとします。`rdm`が起動していなければ起動しておきましょう。

```console
$ rdm --daemon
```

実際に動かしてみるとこんな感じです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/69146/3b2baa53-d15b-c9a5-553a-a59298bacd38.gif" height="400px">

定義へのジャンプはもちろん、参照へのジャンプも自在です。参照のリストはUniteのウィンドウで開かれるので、絞り込みも簡単です。また、rdmはファイルの変更も監視していて、ソースファイルを保存するとインデックスも同時に自動的に更新されます。

## **RtagsをEmacsから使う**

Rtagsには作者製のEmacs用のプラグインが同梱されています。[こちら](http://qiita.com/MitsutakaTakeda/items/2f526a85ad39424a8363)や[こちら](http://qiita.com/alpha22jp/items/90f7f2ad4f8b1fa089f4)にすでに詳しい解説がありますので、ご参照ください。

## **終わりに**

以上、C/C++用インデクサー ["Rtags"](https://github.com/Andersbakken/rtags) の使い方について説明しました。テキストエディタでIDEと同等以上のコードナビゲーションが可能となり、非常に捗ります。セットアップは少し面倒ですが、C++をメイン言語としている方は導入の価値は大いにあると思います。