Makefileの基礎的な活用方法

2024/12/27に公開

導入

Makefileって聞くとどんなイメージをもちますか?
c,c++のビルドツールというイメージを持ってる人も多いですよね。

そのようなイメージを持たれがちなMakefileですが、実はシェルスクリプトを束ねた便利ツールとして使うこともできます。
特に何が便利かというと、所定コマンド実行の前提で必要なコマンド群を定義して、シーケンス制御がさくっとできる点です。

今回は、Makefileの基本的な使い方や、シーケンス制御のやり方を紹介しようと思います。

基本的な使い方

基本構造

Makefileを使うときは、
ターゲット名と依存ターゲットを書いて、その中で実行したいシェルスクリプト群を書きます。
基本構造は下のようになります。

[ターゲット名]: [依存するターゲット名]
    シェルスクリプト群
    ...

[依存するターゲット名]:
    シェルスクリプト群
    ...
...

実行方法

コマンドは make ターゲット名で実行します。

child_target:
	echo 'hello from child_target'

parent_target: child_target
	echo 'hello from parent_target'
make parent_target
echo 'hello from child_target'
hello from child_target
echo 'hello from parent_target'
hello from parent_target

依存ターゲットがないとき

依存ターゲットがないときは依存するターゲット名に何も記載しないです。

single_target:
	echo 'hello from single_target'
	echo 'hello from single_target'
make single_target
echo 'hello from single_target'
hello from single_target
echo 'hello from single_target'
hello from single_target

変数

コマンド実行する中で使う共通変数が定義できます。
変数は即時評価や遅延評価など複数の定義方法があります。

下例は即時評価を使った例です。

ImmVal = 'hello'

child_target:
	echo "${ImmVal} from child_target"

parent_target: child_target
	echo "${ImmVal} from parent_target"
make parent_target
echo "'hello' from child_target"
'hello' from child_target
echo "'hello' from parent_target"
'hello' from parent_target

引数は実行時に渡すこともできます。

make parent_target ImmVal=Yahoo
echo "Yahoo from child_target"
Yahoo from child_target
echo "Yahoo from parent_target"
Yahoo from parent_target

変数の制御は、他にも環境変数や別の評価方法があったりします。

シーケンス制御

ここではシーケンス制御の題材として、前提の子ターゲット処理が成功したときだけ所定ターゲットが実行される一例を記載します。

今回使うMakefileはこちらです。

Val = 0

child_target:
	if [ ${Val} -eq 0 ]; then \
	  exit 1; \
	fi

parent_target: child_target
	echo "hello from parent_target"

上記は変数が初期値のままchild_targetが実行されたときはexit 1 が実行されて失敗するという構成になっています。

ではそのままparent_targetを実行してみます

make parent_target
if [ 0 -eq 0 ]; then \
  exit 1; \
fi
make: *** [Makefile:4: child_target] Error 1

思った通りchild_targetのターゲット内で失敗しましたね。

では今度は実行時引数としてVal=1を指定して、parent_targetを実行してみます。

make parent_target Val=1
if [ 1 -eq 0 ]; then \
  exit 1; \
fi
echo "hello from parent_target"
hello from parent_target

今度は引数が渡されたことで、前提ターゲットが問題なく通ったことで指定ターゲットも実行することができました。

まとめ

今回はMakefileの基本的使い方から、前提ターゲットを記載することでシーケンス制御ができるという一例を紹介しました。
Makefileではターゲット名を宣言して記載できるので、処理ごと目的を名前で表したり、同一ターゲットを複数ターゲットの前提処理として使いまわすことができます。
また、今回の例のようにシーケンス制御ができるので、前提処理の成功を担保した上でコマンド実行をするという構成が作れます。
ほかにもzshユーザなら、zshプラグインでMakefileコマンドの補完の恩恵を受けることもできます。

普段の定期業務で、ポチポチと手動で複数のシェルコマンドを実行するようなケースがあれば、
Makefile活用により業務改善ができるので、ぜひ検討してみてください!

コラボスタイル Developers

Discussion