一、Makefile例子
BUILDDIR ?= build
override BUILDDIR := $(abspath $(BUILDDIR))
.PHONY: all clean
default: src.build
TARGETS=src
all: ${TARGETS:%=%.build}
clean: ${TARGETS:%=%.clean}
%.build:
${MAKE} -C $* build BUILDDIR=${BUILDDIR}
%.clean:
${MAKE} -C $* clean BUILDDIR=${BUILDDIR}
二、变量赋值
例子中使用了= 、:=、?= 三种赋值方式
在 Makefile 中,=
、:=
和 ?=
都是用于定义变量的赋值操作符,它们有以下区别:
-
=
等号赋值操作符,变量的值在使用时会被展开为其赋值时的值。这意味着,如果在后续更改了变量的赋值,那么之前的使用会受到影响。 -
:=
冒号等号赋值操作符表示立即展开赋值。变量的值在赋值时就会被立即展开,而不是在使用时才展开,这种赋值方式可以避免变量之间的互相依赖和不必要的展开操作,提高了效率。 -
?=
问号等号赋值操作符表示如果变量没有被赋值,则进行赋值,这种赋值方式可以用于设置默认值,如果变量在之前已经被赋值,则不会进行再次赋值。这样可以允许用户在命令行或其他地方覆盖变量的默认值。
三、伪目标
例子里定义了两个伪目标:clean和all
在 Makefile 中,.PHONY
是一个特殊的目标,用于声明伪目标,伪目标并不对应任何实际的文件,只是用于触发一系列操作或命令。.PHONY
声明告诉 make 工具,无论是否存在同名的文件,它都应该执行相应的操作。.PHONY
本身并不是一个目标,它只是一个特殊的声明,因此不需要为 .PHONY 指定命令或规则。
四、通配符
例子中使用了
%
和*
通配符
在 Makefile 中,%
是一个通配符,用于匹配模式规则中的部分字符串,可以用于两个地方:
-
在规则的目标或依赖项中使用
%
作为通配符,表示匹配任意字符串。当规则中的目标或依赖项与该通配符规则匹配时,Makefile 将使用该规则进行构建。例子中的%.build:
就是这种用法。 -
变量替换表达式,
${TARGETS:%=%.build}
是一种变量替换表达式,表示将变量TARGETS
的每个字符串替换为相应的以.build
结尾的字符串。
$*
在例子中用于匹配所有目标中%
的内容,例如对于目标src.build来说,$*
会被替换成src
五、递归调用Makefile
例子里使用了
MAKE
这个内置变量
在 Makefile 中,MAKE
是一个内置的 make 变量,它指代当前正在使用的 make 工具的可执行文件名。例如,当你在命令行中运行 make 命令时,make 工具会在环境中设置 MAKE
变量为其可执行文件的名称。在 GNU make 中,通常将其设置为 make
或 gmake
,具体取决于系统和环境设置。
MAKE
变量的存在非常有用,特别是在递归调用 make
时。递归调用 make 是指在 Makefile 中调用另一个 make 命令来处理其他目录或子项目的构建过程。
通过使用 ${MAKE}
,可以确保在递归调用中使用正确的 make 工具。这对于确保子目录中的 Makefile 在正确的上下文中执行非常重要。
-C
表示切换到目录,在例子中可以是src目录build
为切换到目标目录后,要执行的make目标BUILDDIR=${BUILDDIR}
表示将BUILDDIR变量的值传入递归调用的Makefile中