Uncrustifyを使ってObjCコードを整形する

# はじめに

本稿ではUncrustifyを使用してObjective-Cコードを整形するために、 `uncrustify` コマンドのビルド方法や基本的なコマンドの使い方に触れています。

# Uncrustifyとは

[Uncrustify](https://github.com/uncrustify/uncrustify)とは、ソースコード整形ツールの一つです。公式サイトによると、Objective-Cだけでなく、C, C++, C#, D, Java, Pawn, Valaに対応しているようです。

コード整形ツールを活用することで、改行やインデントなどを定めたルール(コーディング規約)を適用し、ソースコードの品質を保つことができます。

# 実行環境

macOSのバージョン

```shell
sw_vers
ProductName:		macOS
ProductVersion:		13.1
BuildVersion:		22C65
```

# Uncrustifyのビルド
## 1. ソースコードのダウンロード

```shell
git clone https://github.com/uncrustify/uncrustify.git
cd uncrustify
# バージョンを指定したい場合はtagをチェックアウト
git checkout uncrustify-0.76.0
```

## 2. ビルド
### cmakeのバージョン

```shell
cmake --version
cmake version 3.25.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).
```

:::note info
cmake 3.19.4+を使うことで、arm64とx86_64両対応のUniversal Binaryをビルドできます。
参考: https://qiita.com/mktshhr/items/c8048b328af6be90f68e
:::

### make

クローンしたuncrustifyのソースコードのルートディレクトリで以下のコマンドを実行します。

```shell
mkdir build
cd build
cmake -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -DCMAKE_BUILD_TYPE=Release ..
```

```
make
```

ビルドに成功すると、buildディレクトリ内に `uncrustify` コマンドが生成されています。

## 3. uncrustifyコマンドにPATHを通す

ビルドに成功した `uncrustify` コマンドを適当なところに格納し、PATHを通します。

PATHが正しく通っていれば、以下のコマンドでUncrustifyのバージョンを確認できます。

```shell
uncrustify --version
Uncrustify-0.76.0_f
```

# コード整形ルールの設定

コード整形ルールは以下のようなKey-Valueを羅列した形式で設定します。
本稿ではuncrustify-objc.cfgというファイル名で保存しています。

```uncrustify-objc.cfg
indent_with_tabs    = 0
output_tab_size     = 4
indent_columns      = output_tab_size
indent_label        = 2
indent_align_assign = FALSE
```

設定できるルールは、以下の記事が非常に参考になります。

https://qiita.com/dfurusaka/items/dd7c5ffdff27451dae16

https://qiita.com/dfurusaka/items/d8998dd5e90697744e3c

https://qiita.com/dfurusaka/items/b3fee3560e4ae746b468

https://qiita.com/dfurusaka/items/1d99d00890baaa35880e

https://qiita.com/dfurusaka/items/aecf5d72a55eef7ed6fe

https://qiita.com/dfurusaka/items/3b0c513718ecd3901306

https://qiita.com/dfurusaka/items/ce7269fe4aa9f34e9a8d

https://qiita.com/dfurusaka/items/ee95487e79a2ca7fb375

https://qiita.com/dfurusaka/items/d1289c116451b709f610

https://qiita.com/dfurusaka/items/cfeda8a49cf8efe48406

https://qiita.com/dfurusaka/items/20a8143322e16d969ca8

https://qiita.com/dfurusaka/items/7b6564cebc60e26701f2


# ObjCコードの整形
## ターミナルで実行

コマンドを実行するディレクトリには以下のファイルがあるものとします。

```
- uncrustify-objc.cfg
- SampleFile.h
- SampleFile.m
```

コマンド実行例を以下に示します。以下の例はSampleFile.mファイルのソースコードを整形します。

```shell
uncrustify -c uncrustify-objc.cfg -l OC SampleFile.m
```

コード整形結果はSampleFile.m.uncrustifyファイルに出力されます。SampleFile.mファイル自体に変更はありません。 `-l OC` はプログラミング言語にObjCを指定しています。

```shell
uncrustify -c uncrustify-objc.cfg -l OC --no-backup SampleFile.m
```

`--no-backup` オプションを付けると、SampleFile.mファイル自体にコード整形を適用し更新します。

## find + xargs + uncrustifyを組み合わせて一括整形

```shell
uncrustify -c uncrustify-objc.cfg -l OC --no-backup ./**/*.m
```

ワイルドカードを使えば一括で整形することができます。ただ、これだとPodsディレクトリ内のソースコードまで整形してしまったりと、少々使い勝手が悪い時があります。

そこで、僕は `find` + `xargs` コマンドと組み合わせて使っています。
以下のようなShellスクリプトを用意します。

```shell:uncrustify.sh
#!/bin/bash

find . \
-type d -name "*.framework" -prune \
-a -type d -not -name "*.framework" \
-o -type d -name "*.xcframework" -prune \
-a -type d -not -name "*.xcframework" \
-o -type d -name "Pods" -prune \
-a -type d -not -name "Pods" \
-o -type d -name "Carthage" -prune \
-a -type d -not -name "Carthage" \
-o -type d -name "build" -prune \
-a -type d -not -name "build" \
-o -name "*.m" \
-o -name "*.h" \
| xargs uncrustify -c uncrustify-objc.cfg -l OC --no-backup
```

上記のスクリプト例では、*.framework, *.xcframework, Pods, buildディレクトリを除外しつつ、すべての.hファイルと.mファイルにコード整形を適用し更新します。 `find` コマンドのオプションは適宜調整してください。

uncrustify.shに実行権限を与えます。

```shell
chmod +x uncrustify.sh
```

このuncrusitfy.shをプロジェクトのルートディレクトリに置いて実行します。

:::note warn
このスクリプトは、ソースコード一式に破壊的な変更を加えるため、実行前に一度コミットしておくことをお奨めします。
:::

```shell
./uncrustify.sh
```

以上でObjective-Cのソースコードを一括で整形することができます。

# 自動コード整形環境の構築

ここまででコマンドを手動実行することで、コード整形ができるようになりました。しかし、このような手順は自動化したいところです。

次回はUncrustifyを応用して、自動でコード整形が走るようにする仕組みを作ります。

次回: [「uncrustify + husky + lint-stagedでObjCコードをコミット時に自動整形する」](https://qiita.com/hituziando/items/630777463877d2d45bcf)

https://qiita.com/hituziando/items/630777463877d2d45bcf