MakefileのPHONYで便利コマンドを書く
- 作成日: 2021-08-26
- 更新日: 2023-12-24
- カテゴリ: Makefile
MakefileのPHONYで便利コマンドを書いたら世界が変わった
Makefileにはターゲットと依存ファイルを記述すると、そのターゲットをビルドするためのコマンドを実行することができます。
さらに.PHONYを書くとダミーターゲットを作ることができます。
ダミーターゲットを使うと、そのダミーターゲットをビルドするためのコマンドを実行することができます。
実際にはターゲットはダミーなので、コマンドのみが実行されます。
つまりMakefileでコマンドだけを実行したい場合は、この.PHONY
でダミーターゲットを作れば可能だということになります。
この記事ではこの.PHONY
とダミーターゲットについて詳しく見ていきます。
具体的には↓になります。
- 普通のMakefileの記述
- 端末から生成するファイルを指定
- .PHONYを使ったダミーターゲットの記述
- ダミーターゲットをサブコマンドとして実行する
- .PHONYの役割と必要性
- 便利なサブコマンドを沢山作る
- サブコマンドをサブコマンド内から実行する
普通のMakefileの記述
普通のMakefileの書き方についておさらいします。
Makefileはビルドを行うためのファイルです。
ビルドとはファイルをコンパイラでコンパイルすることです。
さらにファイルには依存するファイルがあります。
つまり、ビルドには↓の要素が必要になります。
- ビルドするファイル
- ファイルの依存関係
- コンパイルを実行するコマンド
この3つの要素を簡潔に記述できるのがMakefileです。
Makefileではこの3つの要素を↓のように記述することができます。
ビルドするファイル(ターゲット): 依存するファイル
ビルドのためのコマンド
たとえばmain.c
というC言語のファイルがあったとします。
ビルドではこのmain.c
というソースファイルをmain.o
というオブジェクトファイルに変換したいとします。
オブジェクトファイルとはソースコードから生成できる中間形式のファイルのことです。
そしてこのmain.o
を最終的にapp.exe
という実行ファイルにしたいとします。
main.o
はmain.c
とmain.h
の2つのファイルに依存しています。
コンパイラはgcc
を使いましょう。
そうするとこのmain.c
をビルドするためのMakefileは↓のようになります。
app.exe: main.o
gcc main.o -o app.exe
main.o: main.c main.h
gcc -c main.c
↑のコードをMakefile
というファイルで保存し、端末からmake
を実行するとapp.exe
実行ファイルが生成されます。
app.exe
はmain.o
に依存しています。main.o
はオブジェクトファイルです。
そしてmain.o
はmain.c
とmain.h
に依存しています。
Makefileは「app.exe
をビルドするためにはmain.o
が必要だな」と判断します。
そして次に「main.o
をビルドするためにはmain.c
とmain.h
が必要だな」と判断します。
そして「main.c
とmain.h
は存在するからmain.o
をコマンドで生成しよう」となります。
こういう感じでMakefileはビルドを実行していきます。
端末から生成するファイルを指定
さきほどのMakefileで、たとえばmain.o
のみを生成したい場合はどうすればいいのでしょうか?
そういう場合は↓のようにコマンドを実行します。
$ make main.o
こうするとmain.o
のみのビルドが実行されます。
このようにmake
コマンドの引数にターゲットを指定すると、そのターゲットのビルドのためのコマンドが実行されるわけです。
では、ターゲットを生成せずにコマンドのみを実行できればサブコマンドのように使えるのではないか?
という話になりますが、まさにその通りで、そのために.PHONY
を記述します。
.PHONYを使ったダミーターゲットの記述
.PHONY
のPHONY
は「偽物」という意味です。つまりダミーですね。
.PHONY
は↓のように記述します。
.PHONY: ダミーターゲット名
たとえば端末からmake clean
というサブコマンドを実行したいとします。
このサブコマンドはビルドされたファイルを掃除するためのコマンドです。
この場合、Makefileには↓のように記述します。
.PHONY: clean
clean:
rm app.exe main.o
ダミーターゲットをサブコマンドとして実行する
先ほど書いたclean
というダミーターゲットを端末からサブコマンドとして実行します。
そうすると↓のような結果になります。
$ make clean
rm app.exe main.o
rm app.exe main.o
というコマンドが実行されファイルが掃除されました。
このようにダミーターゲットを使うことで色々なサブコマンドを作ることができます。
.PHONYの役割と必要性
では.PHONY
を書かない場合はサブコマンドは実行できないのでしょうか?
結論から言うとできます。
↓のようにMakefileにclean
を書くだけでも端末からmake clean
は実行できます。
clean:
rm app.exe main.o
ではなぜ.PHONY
を書く必要があるのでしょうか?
実は現在のディレクトリ以下にターゲットと同じファイル名が存在する場合、このサブコマンドは機能しません。
たとえば↓のように現在のディレクトリ以下にclean
というファイルを作ります。
そしてmake clean
を実行すると↓のような結果になります。
$ touch clean
$ make clean
make: 'clean' is up to date.
「clean
は更新済み」と表示されてますね。
つまりMakefileがclean
というファイルをビルドするターゲットのファイルとして認識していて、さらにclean
というファイルが存在しているので、結果的にコマンドを実行しないということになります。
このケースではmake clean
はサブコマンドとして実行したいわけですから、ちょっと困るわけです。
そういう時に.PHONY
を使います。
先ほどのMakefileの記述を↓のように戻します。
.PHONY: clean
clean:
rm app.exe main.o
この状態でmake clean
を実行するとちゃんとファイルが削除されます。
Makefileがclean
をダミーターゲットとして認識しているからですね。
便利なサブコマンドを沢山作る
サブコマンドを作れるとなったら色々作ってみたいのが人の心情と言うものです。
たとえば私は↓のようなサブコマンドをよく作ります。
$ make clean
$ make init
$ make full
make clean
は先ほども紹介したビルドされたファイルを削除するコマンドです。
そしてmake init
はビルド環境を初期化するためのコマンドです。これはたとえばbuild/
というディレクトリを作ったり、テストに必要なファイルをbuild/
以下にコピーしたりします。
.PHONY: init
init:
mkdir build/
cp test.txt build/
make full
は各種サブコマンドを呼び出してフルビルドを行うコマンドです。
これについては後述します。
サブコマンドをサブコマンド内から実行する
サブコマンドをサブコマンド内から呼び出すこともできます。
たとえばmake full
というサブコマンドは↓のように書くことができます。
.PHONY: full
full:
make clean
make init
make
↑のようにmake clean
とmake init
, そしてmake
を順々に呼び出しています。
make full
を実行するとまずmake clean
でファイルの掃除が行われ、make init
でビルド環境が初期化されます。そしてmake
で各種ビルドが行われます。
ビルドを1からクリーンな状態で実行したい場合に便利なコマンドですね。
ただ注意点として、最初のビルドはmake full
以外のコマンドで行う必要があります。
これはビルドされたファイルが存在しないとmake clean
が失敗するためです。
おわりに
今回はMakefileの.PHONY
とサブコマンドについて見てきました。
Makefileは扱いになれると非常に便利なツールと言えます。
🦝 < ビルドを自動化できて嬉しいよね
🐭 < せやな