在我們先前的文章中,我們大部分的 Makefile 僅用到變數代換和條件編譯兩項語法特性,其他的特性主要是來自於命令列工具本身。如果我們想要在 Makefile 中使用比前述特性更進階的語法功能,主要有兩個來源:
- 使用命令列工具
- 使用
make
內建的函式
使用命令列工具比較簡單,功能上也比較豐富,但許多好用的命令列工具僅限於類 Unix 系統可用,可攜性相對差。使用 make
內建的函式不需額外安裝其他工具,可攜性比較好,但功能就沒那麼豐富。如果專案皆在類 Unix 系統上編譯,能用的工具會比較多,就不需要刻意學太多 make
內建函式。
如果我們的指令比較複雜,或是要在 Makefile 中多處使用到,可以把這些指令包成巨集 (macro)。Makefile 的巨集基本上就是自訂函式,在巨集同樣可以選擇要用命令列工具或是 make
內建函式,定義好巨集後就可以呼叫該巨集。
以下是 Makefile 巨集版的 Hello World 程式:
define hello
@echo "Hello World"
endef
.PHONY: all hello
all: hello
hello:
$(hello)
使用方式如下:
$ make
Hello World
在這個例子中,我們定義了一個巨集 hello
,定義巨集的一組關鍵字是 define
和 endef
,代表巨集區塊的開始和結束。本例的巨集呼叫系統上的 echo
指令以印出 "Hello World"
字串。
Makefile 的函式呼叫語法如下:
$(function arguments)
# Alternatives
${function arguments}
以本例來說,hello
巨集不帶參數,故以 $(hello)
來呼叫該巨集。
以下是一個帶有參數的巨集:
define assert
@if ! $(1); then \
printf "Failed: $(1)\n"; \
exit 1; \
fi
endef
.PHONY: all true false
all: true
true:
$(call assert,true)
false:
$(call assert,false)
notEqual:
$(call assert,[ "3" -eq "4" ])
在這個例子中,我們用 shell 語法定義了一個 assert
巨集,並且放了三個短例,在 assert
偵測到參數的條件為偽 (false) 時,會引發錯誤並結束程式。在此巨集中 $(1)
代表傳入的第一個參數。呼叫巨集的內建函式是 call
,使用方式可參考範例。
在先前的例子中,我們大部分都用系統的終端機環境所提供的功能,比較容易撰寫,但通用性相對沒那麼好,我們後續會介紹一些 make
內建的函式,對於撰寫 Makefile 的規則、指令和巨集都會有一些幫助。