clang_complete 〜高速化への道〜

さて、以前、vim でコード解析を行うプラグインとして、clang_complete を紹介しました。
補完の精度は優秀ですが、普通に使用すると補完に時間がかかってしまい、ストレスが溜まってしまいます。
clang_complete では、高速にコード解析を行う方法がいくつあるので、今回はそれの検証と結果をまとめたいと思います。

★高速化する方法

1.pch(プリコンパイル済みヘッダー)ファイルを使用する

その名の通り、使用するヘッダーをプリコンパイルして、clang のコード解析時に使用します。
予め、プリコンパイルしておかないとダメなので、ちょっとめんどいかも?

2.libclang

libclangは、llvm に付属しているツールの1つで、コード解析を行います。
Windows であれば、llvm のビルドを行うと libclang.dll が生成される)
clang_complete では、libclang を使用して、高速にコード解析を行うことが出来ます。
ただし、llvm 2.8 では、未対応(?)なので、libclang を使用するのであれば、svn の trunk から、llvm のソースを落としてきてビルドする必要があります。

★検証環境

llvm のビルドオプション

E:\LLVM\llvm-2.8\build>"C:\Program Files\CMake 2.8\bin\cmake.exe" -DCMAKE_BUILD_TYPE=Release \
-DLLVM_TARGETS_TO_BUILD=X86 -DCMAKE_EXE_LINKER_FLAGS="-static-libstdc++ -static-libgcc --disable-shared --enable-static" \
-DCMAKE_SHARED_LINKER_FLAGS="-static-libstdc++ -static-libgcc --disable-shared --enable-static" -G "MinGW Makefiles"

★解析を行うソースコード

#include <cstdlib>
#include <iostream>

#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <boost/signal.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/aligned_storage.hpp>
#include <boost/enable_shared_from_this.hpp>

int main()
{
    boost::    // ←ここで補完を行う
}

※pch を使用する場合は、ヘッダーを分けて行います。

★検証方法

今回は、clang_complete にデバッグ機能として、補完時間を計測する機能が付いているのでそれを使用します。

let g:clang_debug=1

★検証結果

設定 時間(秒)
なし
1.26秒
pch
0.55秒
libclang
-

※libclang は、llvm 2.8 で未対応

設定 時間(秒)
なし
1.07秒
pch
0.52秒
libclang 1回目
8.1秒
libclang 2回目以降
0.45秒

※1回目の呼び出し時に、dll の読み込みを行うので遅いです

★まとめ

単純に高速化したいのであれば、libclang を使うのが一番早いです。
ただし、llvm 2.8 だと libclang は、使用できないみたいなので、svn の trunk から最新版のソースを落としてきてビルドする必要があります。
当然ですが、trunk なので、微妙に動いたり動かなかったりとちょっと怪しいです。
(わたしの場合は、libclang が遅かったので最新のソースを落としてきたら早くなったりしました。)
プロジェクト自体が、プリコンパイル済みヘッダーを使用する前提であれば、それを使用するのもありかも知れません。
あと Boost.Proto 関連(Boost.Lambda や Boost.Spirit 辺り)をインクルードすると libclang でも補完が boooooost します。
これは単に解析に時間がかかっているだけかな?
基本的にコード解析はコンパイル時間に比例すると思うので仕方がないです。
(逆にいえば、コンパイル速度を早くすれば、clang のコード解析も早くなる?)
使用する boost やインクルードしているファイルにもよりますが、かなりストレスは軽減されたと思います。
STL レベルであれば殆ど問題ないかな?


あ、『キャッシングしろ!』とかはいわないでくださいね><
clang のコード解析の仕様上、簡単には行かないと思います……。

★実際の動作

★諸注意

  • llvm をビルドして、libclang を生成する必要が有る
  • llvm 2.8 では、libclang が未対応(多分)
  • svn の trunk から落としてくると微妙なエラーが出たり出来なかったり
  • わたしの使用している llvm 2.9 だと boost/asio.hpp をインクルードするとプリコンパイル時にエラーが出る
  • Boost.Proto 関連(Boost.Lambda とか)をインクルードすると booooost する
  • libclang が高速化するのは2回目以降の補完から
  • neocomplcache との競合が……