🐉

clang-formatの導入手順と使い方

2022/09/11に公開

はじめに

これは何か / 何がいいのか

clang-formatは、主にC++を対象としたソースコード整形ツール(code formatter)である。

https://clang.llvm.org/docs/ClangTools.html#clang-format

ソースコード整形ツールは、ソースコードのフォーマット: コーディングスタイルのうちの見た目に関するものを、一定のルールに従って整形するツールである。ソースコード整形ツールを使うことで、例えばインデントの行い方やカッコの付け方などを手間をかけずに統一できる。チームで開発する際などに、全ソースコードのフォーマットをツールに任せて統一できると、フォーマットに対する好みの差によるソースコードの差分が発生しないため開発効率がよい。

C++用ソースコード整形ツールとして、2022年9月現在で名前がよく知られているのはclang-formatぐらいの様子。

clang-formatでは、整形の行い方をルールファイルで指定する。用意されているスタイル(Google C++ Style Guideなど)を指定するだけでもよいし、細かくカスタマイズしてもよい。

どうやって使うのか

下記のような使い方がある。

  • エディタ上で編集中に整形する
    (この記事では、VSCodeのみを扱う)
  • 所定のタイミングで整形またはチェックを行う
    (例えば、未整形のソースコードのcommitやマージを禁止するなどの運用が考えられる)

導入手順

コマンドラインで使う場合

コマンドラインでclang-formatを使う場合には、名前のとおりのclang-formatコマンドをインストールする。

clang-formatコマンドのインストール

最近のUbuntuやDebianでは、clang-formatが標準パッケージとして提供されているので、それをインストールすればよい。手順は下記のとおり。

sudo apt install clang-format

clang-formatのバージョンを指定してインストールしたいときは、clang-format-12などと指定する。

動作確認

シンプルなルールファイルとソースコードを使って動作を確認する。

ルールは、.clang-formatというファイルに書く。ここでは下記のものを使う。

.clang-format
BasedOnStyle: Google

下記のようなテスト用のソースコードを作成する。整形が行われることを確認するために、ここでは<<演算子の前後の空白を意図的に削っている。

hello.cpp
#include <iostream>

int main(void) {
  std::cout<<"hello, world"<<std::endl;
  return 0;
}

.clang-formathello.cppをカレントディレクトリに置いたら、下記を実行する。

$ clang-format hello.cpp
#include <iostream>

int main(void) {
  std::cout << "hello, world" << std::endl;
  return 0;
}

整形後のソースコードが標準出力に出力されて、<<演算子の前後に空白が挿入されていれば、clang-formatコマンドが正しく機能している。

VSCodeで使う場合

Visual Studio Code上でclang-formatを使う手段はいくつかある。ここでは下記の2通りを扱う。

  • C/C++拡張を使う方法 (広く使われている)
  • clangd拡張を使う方法 (LLVMが公式にリリースしている / 自動整形に若干の制限がある)

なお、Clang-Format拡張もあるが、下記のようにおそらく古いものなので、理由がなければ使わないほうがよいようだ。

  • Extensionとしての最終更新は2019/1/22
  • clangd拡張で置き換えられた、ということなんだろうか。一次情報は特定できず

C/C++拡張による方法

広く使われているC/C++拡張からclang-formatを使う方法。

https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools

C/C++拡張にバンドルされたclang-formatコマンドか、あるいは別途インストールしたclang-formatコマンドのいずれかを使える。

C/C++拡張のインストール

VSCode上で、C/C++拡張をインストールする。

設定は、デフォルトのままで動作する様子。
必要に応じて、C_Cpp.Clang_format_pathを指定する。

任意: clang-formatコマンドのインストール

特定のバージョンのclang-formatを使いたい場合などは、コマンドラインで使う場合と同様に、clang-formatコマンドをインストールする。

clangd拡張による方法

LLVMが公式にリリースしているclangd拡張を使う方法。clang-formatは、clangd拡張の一機能として使用できる。

https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd

clangd拡張を使うためには、clangdサーバを別途インストールする必要がある。

clangdサーバのインストール

最近のUbuntuやDebianでは、clangdが標準パッケージとして提供されている。インストール手順は下記のとおり。

sudo apt install clangd

clangdのバージョンを指定してインストールしたいときは、clangd-12などと指定する。

なお、「サーバ」とあるが、プロセスが常時動作するわけではない。VSCode上で該当する機能を使っているときに、clangd.mainというプロセスが動作するようだ。

clangd拡張のインストール

VSCode上で、clangd拡張をインストールする。

通常は、何も設定変更を行わなくてもそのまま使用できる様子。
必要に応じて、clangd.pathを指定する。

動作確認

コマンドラインツールの場合と同様に、シンプルなルールファイルとソースコードを使って動作を確認する。

下記の2つのファイルをどこかのディレクトリ内に置く。

.clang-format
BasedOnStyle: Google
hello.cpp
#include <iostream>

int main(void) {
  std::cout<<"hello, world"<<std::endl;
  return 0;
}

VSCode上でhello.cppを開き、右クリックを押してメニューを表示し、ドキュメントのフォーマット(Format Document)を選択して実行する。<<演算子の前後に空白が挿入されれば、正しく機能している。

なお、Format Documentの実行は、下記の手順でも行える。

  • コマンドパレットでFormat Documentと入力して実行
  • キーボードショートカットを使って実行
    • LinuxならCtrl-Shift-I、WindowsならShift-Alt-F (手元で確認済み)
    • macOSならShift-Option-Fらしい (未確認)

使い方

ルールファイルの設置

clang-formatclangdは、ルールファイル.clang-formatを下記の順序で探す。

  1. カレントディレクトリにあればそれを使う
  2. ひとつ上のディレクトリにあればそれを使う
  3. 以降ルートディレクトリに至るまで同様に探し、最初に見つかったものを使う

通常は、プロジェクトのルートディレクトリに1つ.clang-formatを置いておけばよい。

ルールのカスタマイズ

ルールファイルはYAML形式で記述する。書き方は下記で詳しく説明されている。

https://clang.llvm.org/docs/ClangFormatStyleOptions.html

おおまかには、下記の順序でルールを決めるとやりやすいと思われる。

  1. 基本スタイル(BasedOnStyle)を選択する
    • GoogleLLVMなどの用意されている選択肢から選ぶ
  2. 基本スタイルのみのルールを使って整形をいくつか試す
  3. 必要に応じて細部を調整する

調整の際には、基本スタイルの設定をダンプして読むと、設定項目とその書き方の参考になる。例えばGoogleスタイルをダンプする手順は下記のとおり。

$ clang-format --style=Google --dump-config > .clang-format
$ cat .clang-format
---
Language:        Cpp
# BasedOnStyle:  Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
...

基本スタイルに調整を加えた設定の一例は下記のとおり。

# Base style is Google
BasedOnStyle: Google

# Force pointers to the type for C++
DerivePointerAlignment: false
PointerAlignment: Left

# No column limit
ColumnLimit: 0
  • DerivePointerAlignment: false + PointerAlignment: Left
    • ポインタや参照を型のように扱う
    • int *a;ではなくint* a;になる
  • ColumnLimit: 0
    • 1行の文字数の上限を無制限にする
    • 横幅を広くしてエディタを使う場合には向いている
    • Webブラウザ上でside-by-side表示を使ってコードレビューをする場合などには向いていない (GitHubなど)

コマンドラインでの使い方

1つまたは複数のファイルにまとめて上書きで適用するなら、下記のように-iオプションを使用する。

clang-format -i file1.hpp dir1/file2.cpp

その他の細かい使い方は、オンラインのヘルプまたはclang-format --helpで表示されるヘルプを参照のこと。

VSCodeでの使い方

手動で整形する

整形対象のファイルを開いた状態で、下記のいずれかを実行する。

  • 右クリックを押してメニューを表示し、ドキュメントのフォーマット(Format Document)を選択して実行
  • コマンドパレットでFormat Documentと入力して実行
  • キーボードショートカットを使って実行
    • LinuxならCtrl-Shift-I、WindowsならShift-Alt-F (手元で確認済み)
    • macOSならOption-Shift-Fらしい (未確認)

自動で整形する

ファイルを保存したときに自動で整形させるなら、設定のeditor.formatOnSavetrueにする。下記のいずれかの手順で設定できる。

  • メニューから選ぶ、あるいはCtrl+カンマを入力するなどして設定(Settings)を開き、テキスト エディター(Text Editor)の書式設定(Formatting)のFormat On Saveを有効にする
  • settings.jsonを編集し、"editor.formatOnSave": trueを足す

C/C++拡張であれば、下記のタイミングでも自動整形できる。(clangd拡張では機能しなかった)

  • 入力時に整形 (editor.formatOnTypetrueにする)
  • ペースト時に整形 (editor.formatOnPastetrueにする)

その他の使い方

例えば下記のような使い方ができる。

整形なしでの特定の操作を禁止して人間に直させるのか、あるいは自動で整形するのかは、方針に応じて選べばよい。

動作を確認した環境

項目 内容
OS, Distribution Debian bullseye (11.4) for amd64
clang-format 11.0.1-2
clangd 11.0.1-2
Visual Studio Code 1.69.1
VSCodeのC/C++拡張 v1.10.8
VSCodeのclangd拡張 v0.1.21
  • 標準パッケージにclang-formatclangdがあることは、Ubuntu 20.04.4 LTSとUbuntu 22.04.1 LTSでも確認済み

Discussion