Emacs で ccls 導入して競プロ

Emacs に ccls を導入しました。

前置き

最近 Emacs と lsp-mode にコーディング環境を移植中なのですが、
競プロをするための環境構築に詰まったので誰かのためになればと書いていこうと思います。
あくまで自分の環境下ではうまく行ったもの (妥協も含む) なのでご容赦ください。。。

イメージ

f:id:granddaifuku:20200914195548p:plain こんな感じで lsp を用いて補完やエラーチェックができるのが目標です。

環境

困ること

LSP (Language Server Protocol) には clang ベースの物しかないです。
(GCC でなんとかならんものかと時間を無限に費やしました。。。)
そこで気付きました。

いや、oj でターミナルは使うやん。
どうせ、gcc で最終的にテストするやん。

ということで、lsp は clang で走らせておいて、補完やエラーチェックなどを行ってもらい、
実際にテストや提出をする前には ターミナルにて gccコンパイルして動作確認をすればいいという結論に至りました。。(妥協)

導入

clang をベースに ccls を導入します。

1.cmake や llvm をインストール

$ brew install cmake
$ brew install llvm


2.ccls のインストール
ccls はどこにインストールしても良いです。(ここでは /usr/local/opt にインストールします。)
(※ Path は通してください)

$ cd /usr/local/opt
$ git clone git@github.com:MaskRay/ccls.git  // https でも全然 OK
$ cd ccls  


3.ccls のビルド

$ mkdir build && cd build
$ cmake -H.. -BRelease -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=/usr/local/Cellar/llvm/<Your llvm Version>/lib/cmake
$ cmake --build Release

ここまでくればもう終わったも同然です。


4.compile_commands.json の生成
ccls は compile_commands.json の内容を元にいろいろとよしなにやってくれます。(気になったら調べてください && そして教えてください)
この json ファイルは cmake で生成できます。
ディレクトリは先ほどの build のままでいましょう。

$ cmake -H.. -BDebug -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_EXPORT_COMPILE_COMMANDS=YES

./Debug/ に compile_commands.json が存在していると思います。
compile_commands.json を実行したい cpp ファイルと同じ階層に置くことで ccls くんがうまいことやってくれます。


(おまけ)
競プロのディレクトリはどうなっていますか??
自分はこんな感じになっています。

$ tree
coder
|- AtCoder
|    |- abc
|        |- abc170
|    |- arc
|    |- ・・
|
|- Codeforces
|    |- #567
(以下略)

軽く説明すると coder ディレクトリ下で AtCoder ディレクトリや Codeforces ディレクトリがあり、各コンテストごとに全てのソースコードが保存してある状態です。

ここで 1 つ問題が発生します。

compile_commands.json を実行したい cpp ファイルと同じ階層に置くことで ccls くんがうまいことやってくれます。

全てのファイルと同階層に compile_commands.json を貼るの面倒すぎでは!?

安心してください。
ccls さまはそんな問題も解決してくださいます。

元々 ccls の設定をプロジェクト全体に適用するための機能1があります。
それを使いましょう。


(i) .ccls-root ファイルを作る
ccls は実は再帰的に上のディレクトリを辿ってプロジェクトルートを探してくれます。
ccls くんに「プロジェクトルートはここだよ」と教えて上げられるのが .ccls-root くんです。
(プロジェクトルートは自分なら coder ディレクトリ)

$ cd <Your project root>  
$ touch .ccls-root

これで OK です。


(ii) シンボリックリンクを貼る
シンボリックリンクについてはこの辺を参照してください。
シンボリックリンクの使い方と落とし穴

$ ln -s /usr/local/opt/ccls/build/Debug/compile_commands.json .

これで ccls の設定を競プロディレクトリ全体に適用することができました。
めでたし、めでたし。


(おまけ part 2)
c++ 競プロer のみなさん bits/stdc++.h 使ってますよね?
(例の include が 1 行で済む魔法のやつ)
ご存知の通り clang にはありません。
つまり、エラーがでます。(悲しい)
無理やり clang がみる include ディレクトリに bits/stdc++.h を作ってしまいましょう。

$ cd /usr/local/Cellar/llvm/<llvm version>/lib/clang/<llvm version>/include
$ mkdir bits && cd bits
$ touch stdc++.h

ここに bits/stdc++.h の内容を貼りましょう。
こことかから拾ってこれます。
(他ソースから拾ってきた場合は(多分エラーが出るので) cstdalign を消すのを忘れないようにしてください)

終わり

ccls を導入してきました。
なんかうまく行かないとか、ここ違ってるぞーなどあれば教えてください。



  1. プロジェクト全体で設定を共有するため、warning などが別ファイルに移動しても常に表示されるのはご了承ください。