【在主画面加入捷径】
       
【选择语系】
繁中 简中

[GNU Make] Makefile 教学:如何使用宏 (Macro) 包装程序代码区块

【赞助商连结】

    在我们先前的文章中,我们大部分的 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 的守则、指令和宏都会有一些帮助。