本系列文章均翻譯自make官方文檔:make Manual,github同步項目:question
-
變量名是大小寫敏感的。
-
推薦大寫的變量名來控制隱含規則或者用戶使用命令行時會覆蓋的參數;小寫變量名在Makefile內部使用。
變量引用基礎
$(xxx)
與${xxx}
都是可以的。
在文件名或recipe中寫入$
符號必須鍵入$$
。
變量的兩種類型
- recursively expanded變量。使用
=
(單行)或define
(多行)定義變量。
缺點:CFLAGS = $(CFLAGS) -O
- 會引起自循環,make會檢測到自循環並報告一個錯誤。
- 每次變量被擴展的時候任何在定義中的函數(see Functions for Transforming Text)引用都會執行。會引起wildcard和shell函數給出不可預知的結果。
- simply expanded變量,可以解決上述的缺點。使用
:=
或::=
來定義。只有::=
被POSIX標準支持。對於所有引用該變量的其它變量或者函數,它只會被掃描一次。
例:
x := foo
y := $(x) bar
x := later
結果:
y := foo bar
x := later
區別:make在執行定義recursively expanded variable時,不會擴展該變量中的引用變量,只有在引用該變量的時候引用變量纔會被擴展;simply expanded variable則是在定義變量的時候就已經將引用變量擴展了。
還有另一種定義操作?=
,條件賦值變量,如果該變量沒有被定義過,那麼纔會被賦值。
FOO ?= bar
等於
ifeq ($(origin FOO), undefined)
FOO = bar
endif
note:變量被賦予空值的話,它仍然是被定義了。所以?=
不會被設置變量。
引用變量的高級特性
替換引用
格式$(var:a=b)
(or ${var:a=b}
)會導致替換掉var的值中用b替換a。
可與patsubst
結合使用。
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
結果:bar = a.c b.c c.c
計算變量名
變量可能被引用在一個變量名中。這叫做computed variable name或nested variable reference。
這種方式的唯一缺點就是不能指定被調用的函數名。???
執行shell腳本
!=
可用於執行shell腳本並把輸出設置爲變量的值。
hash != printf '\043'
file_list != find . -name '*.c'
如果結果中含有$
,並且不想使其擴展爲make變量,那麼必須替換爲$$
。你也可以使用shell函數(See The shell Function)。
hash := $(shell printf '\043')
var := $(shell find . -name "*.c")
向變量添加內容
向一個已經定義的變量中添加內容:
objects = main.o foo.o bar.o utils.o
objects += another.o
變量沒有被定義時,+=
相當於=
。
如果定義了,取決於變量類型。
override指令
如果使用命令行參數設置了變量,那麼在makefile中的設置將被忽略。override
可以打破這個規則。
override variable = value
比所有其它方式定義的變量的優先級都要高。
用來提示並添加用戶指定的命令行參數:
override CFLAGS += -g
結合define使用:
override define foo =
bar
endef
定義多行變量
define two-lines =
echo foo
echo $(bar)
endef
當在recipe中使用此種變量時,相當於
two-lines = echo foo; echo $(bar)