ハトネコエ Web がくしゅうちょう

プログラミングやサーバー関連、チームマネジメントなど得た技術のまとめ

Makefile の = と := と ?= (makeの基礎)

問題です!

以下のような Makefile があったとして、
それぞれの make test の出力結果は何になるでしょう?

Q1. =

x = foo
y = $(x) bar
x = later

.PHONY: test
test:
   @echo $(x)
   @echo $(y)

Q2. :=

x := foo
y := $(x) bar
x := later

.PHONY: test
test:
   @echo $(x)
   @echo $(y)

Q3. ?=

x ?= foo
y ?= $(x) bar
x ?= later

.PHONY: test
test:
   @echo $(x)
   @echo $(y)

ヒント!

ドキュメントです!

GNU make - How to Use Variables

答え

というわけで、上のドキュメントがわかりにくかったので
自分なりにまとめたかったための、この記事でした。

= (equal) , := (colon equal) , ?= (question mark equal) の挙動はすべて異なります。
特に = がよくあるプログラミング言語とは異なる挙動を示すので注意です。

A1. =

x = foo
y = $(x) bar
x = later

.PHONY: test
test:
   @echo $(x)
   @echo $(y)

答えは

later
later bar

です。注意すべきは、y の中身が「later bar」になっていることですね。

make において = は recursive expansion再帰的な展開)がなされます。

y = $(x) bar と定義したとき、 x の値が更新されるたびに y の値は更新されるのです。
なので、 x = later と再定義されたことで最初の x = foo はもはや関係なく、 y の値は「later bar」となっているのです。

A2. :=

x := foo
y := $(x) bar
x := later

.PHONY: test
test:
   @echo $(x)
   @echo $(y)

これの出力は

later
foo bar

です。一番わかりやすいのではないでしょうか。

ドキュメント上でも

Simply expanded variables generally make complicated makefile programming more predictable because they work like variables in most programming languages.

意訳すると『このシンプルな変数の展開は、多くのプログラミング言語での変数と同様の挙動をするので、複雑な Makefile をわかりやすくできます』といったことが書かれています。
Makefile での変数定義で := が使われることの多い理由がよくわかりました。

なお、もし1行目がない場合、つまり

y := $(x) bar
x := later

となっていた場合、未定義の x は空文字として処理されます。ですので y の値は「bar」の文字列になります。

A3. ?=

x ?= foo
y ?= $(x) bar
x ?= later

.PHONY: test
test:
   @echo $(x)
   @echo $(y)

最後のこちらの答えは

foo
foo bar

です。x が「foo」のままなのがポイントですね!

?=変数がまだ未定義のときのみ代入をおこなう演算子です。
最近のプログラミング言語ではこのような機能の演算子を実装されているものが多いですね。

なお、make のドキュメント上では conditional variable assignment operator条件付き代入演算子)と呼ぶそうです。

おわりに

make は昔からあるツールながら、ほとんどの環境にビルドインされているぶん、
Docker や AWS コマンドなど長いコマンドを呼び出すことの多い昨今においても、
ビルドツール以外の使われ方として好まれて使われます。

一方で、私のような若輩者にとって Makefile の書き方は正直わからず、
今回の変数定義の話になりました。 := がよく使われる理由がわかってスッキリです。

冒頭のクイズ、周囲のプログラマー仲間に出題してみると面白いかもしれませんよ!


Vue.js、完全に理解した(い)!【プログラミング実況・はじめての Vue.js編 #2】

最近はこんなのもやってます!