MacのSublime Text 3でもclang使って整形とか補完とかしたい

clang-formatによるコード整形

MacのCommand Line Toolsにはclang-formatがない。clang-formatというのはその名前の通り、ソースコードをclangに静的解析させて自動で整形しようというツール。

対応しているコーディングスタイルは次の5つ。

  • LLVM
  • Google
  • Chromium
  • Mozilla
  • WebKit

また、全く独自のコーディングスタイルを設定することもできるし、あるいはこれらのコーディングスタイルを元に一部を自分好みに変更した設定も可能である。かなり自由。

さて、これ別に自分でコンパイルする必要もなく(LLVMとclang自体が)バイナリ形式で提供されていたりする。便利な世の中だ。LLVM Download Pageから入手できる。Mac向けは"Clang for Darwin"。

ダウンロードしたファイルを適当なフォルダに展開してパスを通せばclang-formatが使えるはず。なおclang-format以外のものも全部パスが通った場所に置いた場合のシステムの挙動は確かめてない(別にどうってことはないかもしれないし、どっかで何かおこるかもしれない)。

Sublime Textとの連携については公式からプラグインが提供されている(なぜかドキュメントには言及がないが……)。

まずはツリーから当該のプラグインを落としてくる。 -> https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/clang-format-sublime.py

ソースコード冒頭に簡単な説明があるのでそれに従う。まずはこのファイルを~/Library/Application Support/Sublime Text 3/Packages/User以下に入れる。次にSublime TextのPreferences -> Key Bindings - Userを選んでキーバインドの設定ファイルを開き次の一行を追加する(説明ではCtrl+Shift+Cになっているのでそのようにしたが適宜変える)。

{ "keys": ["ctrl+shift+c"], "command": "clang_format" }

これでclang-formatにパスを通してあれば動くはずなのだがなぜか動かなかった。clang-formatがないというエラーメッセージが出ていたので、説明から少し下にあるbinaryの値をフルパスに変更して無事に動作した。

なお、このとき使われるコーディングスタイルは.clang-formatを参照する設定になっている(binaryのもう少し下にstyleの設定があり、これが’file’となっている)。style=fileとなっているのに.clang-formatファイルが存在しない場合、LLVMスタイルが選択される。clang-format-dump-configオプションで設定を出力できるのでこれを.clang-formatとして出力させつつ適宜スタイルを修正すると幸せになれる予感がする。

コード補完

(コードを読み書きする人間を除いて)コードの解釈を一番よく知っているのはコンパイラなんだから、コンパイラにコード補完のバックエンド的な役割をさせようという話。Haxeのコンパイラはこの仕組みを持っていて、コンパイラがサーバーとして動作して、そこにリクエストを投げると型情報やら何やらを返してくれる、という機能がある。あったはず。

同じ事をclangでやろうというお話なのだが、ググると主に紹介されているquarnster/SublimeClangはREADMEの初っ端にPlugin discontinuedと書かれている。オワコン。

そんなわけで同じ作者の後継作たるquarnster/completionを試す。

まず大前提としてこれGoで書かれているのでGoの環境が必要である。公式のパッケージもあるし、Homebrewでもインストールできる。あと今回の場合はgitとMercurialも必要。

普段Goを書いてないからかもしれないが、Goの開発環境の構築はちょっとクセがあるように見える。環境入れてコンパイラとかにパス通してはいおしまい、とはいかない。ドキュメントに沿って進める。(Homebrewでインストールしたときもこれ読めというメッセージが出るはず)

まずホームフォルダにgoフォルダを作る。そしてGOPATHという環境変数を設定する。ついでに$GOPATH/binにもパスを通しておく。

$ mkdir $HOME/go
$ export GOPATH=$HOME/go
$ export PATH=$PATH:$GOPATH/bin

環境変数の設定は.bashrcなり.zshrcなりに書いておいた方がよいと思う。ここまで済ませた上で

$ go get -d github.com/quarnster/completion

とするとお目当てのソースコードの他依存しているパッケージのソースコードもごそっと落としてくる(このときにMercurialとgitが必要になる)。

さて、これで$GOPATH/src/github.com/quarnster/completionにcloneされている。ビルドするにはbuildディレクトリに入ってmakeすればよい。

$ cd $GOPATH/src/github.com/quarnster/completion/build
$ make

ビルドに成功すると同じディレクトリにcompletionというバイナリが生成されている。Sublime Textにプラグインとしてインストールするにはそのまま

$ ./completion install -st

とする。Sublime Textの場所を探し出していい感じにインストールしてくれる(2と3を共存させていても両方にインストールする)。

あとはC/C++でのコーディングをお楽しみください。

余談

ClangComplete

ちなみに別のclangを用いたプラグインにpfultz2/ClangCompleteというのがあったが、どうにも動かなかったので諦めた。というのもこのプラグインおおよそLinuxの方しか向いていないようにしか思えない状態だった。一応ある程度のところまで作業したのでメモしておく。

まずこのリポジトリ自体をそのままSublime Textのプラグインディレクトリにcloneする。その後ClangComplete/completeディレクトリに移動してmakeすると見事に失敗する。

Python3.3のヘッダーファイルが見つからないと言っているのでPKG_CONFIG_PATHを設定する。HomebrewでPython3.3が入っていれば(なければ入れる)、/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/pkgconfigにある(3.3.3の辺りはバージョンによる。これ更新されたらどうなるんだ)。

PKG_CONFIG_PATH=/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/pkgconfig

次、clangのヘッダファイルがないと言い出す。Makefileを編集する。CLANG_PREFIXを設定している箇所を消して、上で述べたclang+llvmのバイナリパッケージを展開したディレクトリを指定する。仮に$HOME/clangに置いたとすればCLANG_PREFIX=$HOME/clangとする。

次、std::vectorなんてものはないというエラーが出まくる。そんなアホなと思ってcomplete.cppを見てみると#include <vector>がない。適当な場所に追加する。

(ちなみにこれ、gccでは通ったりするのだろうか。少なくとも大学のLinuxマシンに入っていたgcc 4.1.2でもエラーを吐いたが)

次、-sonameなんてオプションは知らないと言い始める。これは単純に-soname-install_nameに置換してしまえばよい。 参考: osx - CMake: Mac OS X: ld: unknown option: -soname - Stack Overflow

次、-rpathなんてオプションも知らないと言い出す。これは一旦-rpathを削除してしまう(-Wl,-rpath...でひとつのオプションなのでこのかたまりを消す。-Wlはリンカーに渡すオプションを指定するオプション)。いろいろ探し回った挙げ句、どうもこれを代替する手段はなさそうだった。

これでコンパイルが通る。だが実際にSublime Textを動かしてみると何も起きない。コンソールを確認するとlibclang.dylibが見当たらずにlibcomplete.soのロードが失敗している。前の段階で-rpath(ランタイムパスの指定)を消してるんだから当たり前だ。これを無理矢理にでも(今回の場合は)$HOME/clang/libを見に行かせる必要がある。

そうして見つかったのがDynamic Libraries, RPATH, and Mac OS (Joe Di Pol’s Blog)という記事だった。これを読んだところ、install_name_toolというツールが備わっているのでそれを使ってlibcomplete.soを弄ってしまえばよさそうという感触。ただまぁ使い方も何もさっぱりわからないのでいろいろ試したところ、

$ install_name_tool -add_rpath $HOME/clang/lib libcomplete.so

libcomplete.soのロードに成功した。

が、いざコードを編集しようとするとプラグインが即死する。やはり世の中そう上手くは行かなかった。

もうよくわからなかったしこれ以上格闘してても無駄な気がしたので私はここでcompletionを使うことにした。のでプラグイン即死の理由とかその解決方法がわかったら@maytheplicまでリプください(真顔)。

clang+llvmのディレクトリ構造

clang+llvmのビルド自体はドキュメントを読めば割と簡単にできるのだけど、あのディレクトリ構造は永遠に理解できないかもしれない。