読者です 読者をやめる 読者になる 読者になる

marching.vim でプリコンパイル済みヘッダーを使用して C++ のコード補完を高速にする

先日、Clang でコンパイル済みヘッダーを試したのですが、これを marching.vim でも使ってみたいと思います。 今回はひとつのプリコンパイル済みヘッダーファイルを共有して使ってみます。

[プリコンパイル済みヘッダーを作成する]

適当なディレクトリにヘッダーファイルを作り、プリコンパイルしたいヘッダーファイルを記述します。

// ~/cpp/pch/header.h
#include <iostream>
#include <vector>
#include <map>
#include <regex>
#include <tuple>
#include <regex>
#include <string>
#include <type_traits>
#include <functional>
#include <memory>
#include <sstream>
#include <algorithm>
#include <thread>

これをプリコンパイルします。

$ clang++ -std=gnu++1y c++-header header.h -o header.h.pch

これで header.h.pch が生成されたので、これを共用して使用します。

[marching.vim の設定]

marching.vimg:marching#clang_command#options でプリコンパイル済みヘッダーを指定します。

" marching.vim のコマンドオプションを設定
let g:marching#clang_command#options = {
\   "cpp" : "-std=gnu++1y -include-pch ~/cpp/pch/header.h.pch"
\}

[使い方]

通常と同じように補完が行われます。
また <header.h> をインクルードする必要はなく、 <string> などをインクルードするだけで使用できます。
(なので header.h.pch を共用のプリコンパイル済みヘッダーとして使用できます。

[パフォーマンス比較]

marching.vim からでは検証しづらいので、コマンドから -code-completion-at= を使って調べてみます(marching.vim 内部でも同様のことをしています。

[検証ファイル]

// header.h の一部のヘッダーファイルをインクルードする
#include <functional>
#include <memory>
#include <algorithm>
#include <thread>

int
main(){
std::
    return 0;
}


// clang++ -std=gnu++14 -fsyntax-only -include-pch main.h.pch  -Xclang -code-completion-at=main.cpp:5:9 main.cpp

[プリコンパイル済みヘッダーなし]

$ clang++ -fsyntax-only -std=gnu++1y -Xclang -code-completion-at=main.cpp:8:6 main.cpp

...
    
real    0m0.557s
user    0m0.358s
sys 0m0.053s

[プリコンパイル済みヘッダーあり]

$ clang++ -fsyntax-only -std=gnu++1y -include-pch ~/build/cpp/pch/header.h.pch  -Xclang -code-completion-at=main.cpp:8:6 main.cpp

...
    
real    0m0.380s
user    0m0.076s
sys 0m0.028s

こんな感じで約 1.5 倍ほど早くなりました。

[プリコンパイル済みヘッダーを使う上での注意点]

[速度がプリコンパイル済みヘッダーを使わない時よりも遅い時がある]

どういう時かというと『コード量が少ない時』ですね。
極端に言うと『ヘッダーファイルをインクルードしてない』コードの場合は、『プリコンパイル済みヘッダーを使ってる』方が遅くなります。

[インクルードしてないヘッダーファイルの候補も出力される]

ヘッダーファイルをインクルードしてなくてもプリコンパイル済みヘッダーの方でインクルードしていれば、その候補も出力されてしまいます。

[まとめ]

いくつか注意点はあるんですが、パフォーマンスはかなり改善されるので使い得だと思います。
特に今回は使いませんでしたが、boost を使った場合では補完速度が劇的に改善されました。