GNU Make 相容的 Makefile 教學:巨集 (Macro)

PUBLISHED ON JUN 26, 2018 — BUILD AUTOMATION

在我們先前的文章中,我們大部分的 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,定義巨集的一組關鍵字是 defineendef,代表巨集區塊的開始和結束。本例的巨集呼叫系統上的 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 的規則、指令和巨集都會有一些幫助。

comments powered by Disqus