リポジトリのセットアップや、docker composeを使った開発環境のローカル起動などに
シェルスクリプトを使う人は多いだろう。
ただ、以下のような悩みは無いだろうか?
./bin/〇〇.sh
が量産されて、どれが何だっけ?とよく混乱する- ↑の使い方を分かりやすくするために、READMEを都度メンテしなくてはいけない
- 実行に必要なファイルの存在チェックをシェルスクリプトで書いて消耗する
- コマンドの依存関係をREADMEで説明するのが面倒
Makefileはこの悩みを全て解消する。
Makefileとは
本来「C言語のコンパイルから実行までをコマンド一つで実行しよう」というものである。
しかし、特徴として「ショートカットコマンドを量産できる」ので
1つのコマンドが長くなりがちな
DockerコマンドやPython(仮想環境)の実行コマンドに相性が良い。
シェルスクリプトとの比較
シェルスクリプトと比較したときのメリデメは以下の通りだ。
見て分かる通り、デメリットはほぼ無いに等しいのでMakefile推しである。
メリット
- 書き方や実行のルールが決まっているので、他の人も読みやすい(Makefileそのものがドキュメントとして機能する)
- 例:
start.sh
とかstop.sh
など複数ファイル用意することなく、全てMakefile
ファイルで完結
- 例:
- 実行時に必要なファイルをチェックしてくれるので、バリデーション処理を自前で書かなくて良い
- 例: 実行前に
.env
ファイルの存在チェックをしたい
- 例: 実行前に
- コマンド間の依存関係を定義することができる
- 例:「ビルドしてから実行する」
デメリット
- makeコマンドのインストールが必要→
brew install make
でOK - 文法を覚える必要がある→この記事の内容で十分
- 実行時に引数を扱うことができない→「同じ内容で長いコマンド」を省略したいだけなので特に困らない
実行方法
Makefile
という定義ファイルを作成Makefile
があるディレクトリで、「make 任意のコマンド名
」を実行する
Makefileの書き方
コマンド名: 実行に必要なファイル
実際に実行するコマンド
ポイントは3つ
- 「実行に必要なファイル」は、省略可能。ただし記載しておくことでファイルチェックをしてくれる
- 「実際に実行するコマンド」の先頭はスペースではなくtabにする必要がある
- 実行するときのコマンドは「
make コマンド名
」
実行例
Makefile
hello:
echo "hello"
実行結果
$ make hello
echo "hello"
hello
応用編
シンプルなショートカットコマンドの定義だけであれば、上記の説明で困ることはない。
ここからは少し複雑なコマンドを定義したいときに必要なことを解説する。
①makeコマンドは続けて実行可能
Makefile
hello1:
echo "hello1"
hello2:
echo "hello2"
実行結果
# 「make コマンド1 コマンド2 ...」というふうに続けて実行可能
$ make hello1 hello2
echo "hello1"
hello1
echo "hello2"
hello2
連続して実行することができるので、定義するコマンドは最小単位にしておくとスマート。
②必要なファイルはスペース区切りで複数指定できる
Makefile
build: Dockerfile test.txt
docker build -t python-sample:1.0 .
ディレクトリにDockerfile
は存在するが、test.txt
は存在しない場合、以下のようにエラーが発生する。
$ make build
make: *** No rule to make target `test.txt', needed by `build'. Stop.
③変数を使うことも可能
定義するときは「変数名 = 値」
利用するときは「$(変数名)
」で使うことができる。
Makefile
MESSAGE = "hello, world."
hello:
echo $(MESSAGE)
実行結果
$ make hello
echo "hello, world."
hello, world.
④コマンド同士の依存関係も自動で解決してくれる
先述した基本コマンドの「必要なファイル」という部分は
実はファイルに限らず、他のmakeコマンドも定義することができる。
これにより、「コマンドAを実行するためにはコマンドBを実行しておく必要がある。だからコマンドB実行→コマンドA実行という流れで実行しよう。」という定義を行うことができる。
Makefile
# 実行するためには、ビルドの手順が必要だと定義する
run: build
echo "実行します"
build:
echo "ビルドします"
実行結果
# 実行用のrunコマンドを実行する
$ make run
echo "ビルドします"
ビルドします
echo "実行します"
実行します
run
前にはbuild
が必要なため、build
を自動で実行し、その後にrun
を実行するようになる。
まとめ
- Makefileは長いコマンドをショートカットするのに便利
- 「実行前に必要なものが揃っているか?」を定義することができる
- READMEの追記と
〇〇.sh
の量産に悩まされたらMakefileを使おう