6.變數

ignorantshr發表於2019-01-06

本系列文章均翻譯自make官方文件:make Manual,github同步專案:question

  • 變數名是大小寫敏感的。

  • 推薦大寫的變數名來控制隱含規則或者使用者使用命令列時會覆蓋的引數;小寫變數名在Makefile內部使用。

變數引用基礎

$(xxx)${xxx}都是可以的。
在檔名或recipe中寫入$符號必須鍵入$$

變數的兩種型別

  1. recursively expanded變數。使用=(單行)或define(多行)定義變數。
    缺點:
    • CFLAGS = $(CFLAGS) -O
    • 會引起自迴圈,make會檢測到自迴圈並報告一個錯誤。
    • 每次變數被擴充套件的時候任何在定義中的函式(see Functions for Transforming Text)引用都會執行。會引起wildcardshell函式給出不可預知的結果。
  2. 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 namenested 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)

相關文章