2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C言語の開発環境構築メモ(macOS + VSCode)

Posted at

C言語の開発環境構築はVisual Studioを入れるのが一番手っ取り早そうなのだが、macOSの場合はVisual Studioが現在対応していない。
そのため、VSCodeで色々頑張る方法を模索した。

コンパイラ

clangはmacOSの場合、デフォルトで入っている。
gccを使いたい場合はインストールする。

shell
$ brew install gcc

コンパイラ警告

C言語の場合、コンパイラの警告を見るのがプラクティスとして重要になってくる。
デフォルトでは大した警告を出してくれないので、フラグを与えることで警告の種類を増やす必要がある。

ひとまず重要なフラグとして-Wall-Wextraがある(gccもclangも共通)。
-Wallによって全ての警告がオンになる……わけではなく、これは"基本的な警告が"全てオンになる、的な感じでしかないらしい。
なので、ここから漏れた警告として-Wextraを足す必要がある。
これで今度こそ全ての警告がオンになる……というわけでは全く無く、まだまだ足した方が良い大事な警告がこの世にはたくさんあるらしい。
世界は広い

clangの場合、-Weverythingという最強のフラグがある。
今度こそ全ての警告がオンになった……と思うのだが、いかんせん今度はあまりにも警告が細かくてうるさい。
幸い、警告を指定してオフにするフラグを後ろに追加していくこともできるので、結果として「全マシのニンニク抜きアブラ抜き」みたいな感じになってくる。

どっちにしろ、ベストのフラグ構成を目指そうとするとかなりの沼になる。
とりあえず-Wall -Wextraで妥協して先に進むことにする。

Makefile

スタバの呪文みたいな大量のフラグをコンパイルの度に渡さないといけない運用もアレなので、Makefileを導入する。
Makefileはプロジェクト毎に作成する。

とりあえずは必要最低限の、コンパイラフラグをキープするためだけのMakefileを作成した。

Makefile
CC = gcc
CFLAGS = -Wall -Wextra

main:
	$(CC) $(CFLAGS) -o main main.c
shell
# `./main`が生成される。
$ make

VSCodeの拡張

Microsoftの「C/C++」拡張がすごいスタンダードな空気を醸し出しているが、どうやらLLVMの「clangd」拡張の方が高性能らしい。
私は両方試そうとしたが、未使用の変数に警告を出す(後述するが、つまりコンパイラ警告をリンターで表示する)のが前者ではどうしても上手くいかず、後者にしたら一発で上手くいったので、後者をメインで使っていくことにした。

ただし、デバッグ関係の機能とかは「C/C++」拡張にしか無いので、両方インストールしておくのが良いらしい。
「C/C++」拡張をインストールした状態で「clangd」拡張をインストールすると、ポップアップで「Microsoftの方のやつも入ってんねんけど。特にインテリセンス機能がウチと競合してるさかい、こいつウチが黙らせてええか?」的なことを聞かれるので、「Yes」を押すと、VSCodeのsettings.jsonに以下の項目が追加される。

settings.json
{
    "C_Cpp.intelliSenseEngine": "disabled"
}

これで無事両立ができた。

必要なバイナリ

イカれたメンバーを紹介するぜ!(訳:前提となる用語の解説)

  • LLVM: 任意のプログラミング言語に対応可能なコンパイラ基盤。
  • clang: LLVMを使った、CとかC++とか向けのコンパイラ。
  • clangd: 言語サーバー。エディタ向けの機能とか提供するやつ。
  • clang-tidy: リンター。clangdにも組み込まれている。
  • clang-format: フォーマッター。clangdにも組み込まれている。

さて、clangclangdはmacOSの場合デフォルトで入っている。(Xcode Command Line Toolsのインストールが必要かも。)
VSCodeの「clangd」拡張はclangdがあれば動くので、特に追加でインストールするものはない。

clang-tidyclang-formatについて。これらのバイナリはmacOSにはインストールされていない。
VSCodeの「clangd」拡張を動かす分には、clangd経由でこれらの機能が呼ばれるため、clang-tidyclang-formatといった個別のバイナリは必要ない。
だが、なんとなくコマンドラインからもこれらの機能を呼びたいと思ったなら、インストールする必要がある。

clang-tidyclang-formatは個別にインストールすることもできるが、以下のコマンドでまとめてインストールすることができる。

shell
$ brew install llvm

バイナリは/usr/local/opt/llvm/binにインストールされる。
デフォルトではここにパスが通っておらず、自分で通す必要がある。
(この辺の話はインストール後にHomebrewがCaveatsとして表示してくれる。)

ここで注意。上では「まとめてインストール」と書いたが、ここにはclangとかその他色んなバイナリも含まれる。
特にclangはmacOSの組み込みのもの(/usr/bin/clangd)と2つ存在することになる。
上記のようにパスを通し、インストールしたclangが組み込みのものより優先して呼ばれるようになることで、どこかで何かトラブルを起こす可能性がある。
私の環境では今のところ問題は起きていないが、この辺は自己責任でお願いしたい。

フォーマッター

VSCode自体の設定になるが、editor.formatOnSaveはお好みでtrueにしておくと良い。
言語毎に設定を変えることもできる。

さて、C言語の書式のスタイル標準は乱立している。
ということでclang-formatでは、書式をいちいち細かく指定することができる。
コマンドならば引数で直接設定したりもできるが、主な方法としては.clang-formatというYAMLファイルを設置することになる。

.clang-formatはプロジェクトフォルダに置いてもいいし、プロジェクト毎に設定する気がないなら親フォルダに置いてもいい。
(clang-formatは対象ファイルのあるフォルダから出発して、順に親フォルダへと遡りながら.clang-formatを探し、最初に見つけたものを採用する。)

上では「細かく指定」と書いたが、基本的にはどれかのスタイル標準を選ぶだけで事が足りるだろう。
.clang-formatで指定できるオプションの中にはBasedOnStyleという項目があり、以下のいずれかの標準を指定できる。1

LLVM, Google, Chromium, Mozilla, WebKit, Microsoft, GNU

ということで、とりあえずこんな感じの.clang-formatを用意すれば良い。

.clang-format
BasedOnStyle: Microsoft

リンター

clang-tidyの診断項目は1つ1つに名前がついており、個別にオン・オフを設定する事ができる。
これもまたコンパイラ警告と同様、初期状態では全てオンにはなっていない。そんでもって全てオンにするとかなり鬱陶しい。
従ってこれもベストの設定を探る余地がある。
設定は.clang-formatの時と同じように.clang-tidyを設置することで行える。

個人的に触れておきたいのはreadability-identifier-namingという診断項目で、各識別子のCasing(CamelCaseとかUPPER_CASEとか)を細かく設定してチェックする事ができる。
フォーマッターでは強制できなかった命名規則もこれでルール化できそうだ。

そして、重要な診断項目としてclang-diagnostic-*シリーズがある。
これはclangコンパイラによる診断という事らしく、そのほとんどがコンパイラ警告に対応している。
例えばclang-diagnostic-division-by-zeroは、clangに-Wdivision-by-zeroを渡すことで有効になる警告と同じ内容の診断項目だ。(他の診断項目も全てこのような命名対応規則に従っている。)
clang-tidyの診断結果はVSCodeの「clangd」拡張によってリアルタイムに波線で表示されるので、いちいちコンパイルしなくてもコンパイラ警告の内容を確認できるということになり、ありがたい。

しかし、clang-diagnostic-*シリーズの診断を行うには注意点がある。
clang-tidyのベースとして動いているclangに適切なコマンド引数(特に警告レベルのフラグ)を与える必要があるのだ。
例えば未使用の変数を検出するためには、.clang-tidyclang-diagnostic-unused-variableをオンにするだけではダメで、clangに-Wunused-variableかあるいは-Wall等を渡さないといけないことになる。
では具体的にどうすればベースのclangにコマンド引数を渡せるのかというと、コンパイルデータベースと呼ばれるファイルをプロジェクト内に設置するのである。

コンパイルデータベースの作成

compile_commands.jsoncompile_flags.txtの2通りがあり、後者の方が簡易版となる。

先に簡易版のcompile_flags.txtについて説明すると、これは非常に単純で、単に渡したい引数を以下のように改行して羅列するだけだ。

compile_flags.txt
-Wall
-Wextra

しかし、Makefileと多重管理になる点が面倒になってくる。

次にcompile_commands.jsonで、これは書き方がもっと具体的かつ本格的な感じになってくるわけだが、これに関しては「Bear」というツールで自動生成する事ができる。

shell
$ brew install bear
shell
$ bear -- make

こうすれば、makeによって走るビルドプロセスをbearが監視し、良い感じのcompile_commands.jsonを生成してくれる。
これで無事Makefileとの多重管理を避けられた。

ちなみに、Makefileの中でgccを使ったビルドを指定している場合、compile_commands.jsonの中身もgccによるコンパイルの設定が記述されるが、clang-tidy側のclangはその辺も読み取った上で上手く合わせた実行をしてくれるっぽい。

デバッガー

使ってないから分かんない。(「C/C++」拡張を無理にインストールした意味がここで無くなる。)

完成

もう何も恐くない。

  1. InheritParentConfigという、親フォルダの.clang-formatの設定を引き継ぐことを指定する値もある。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?