位元詩人 [GNU Make] Makefile 教學:如何使用巨集 (Macro) 包裝程式碼區塊

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

在我們先前的文章中,我們大部分的 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 的規則、指令和巨集都會有一些幫助。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。