基本语法

# 这里的先决条件,要么是存在的文件、要么是一个target
targets: prerequisites
	command
	command
	command

⚠️ command前需要有一个Table

# target-a会被执行
target-a:
	command
target-b:
	command
# 通过这里定义的all一次性执行三个没有独立的target
all: one two three

one:
	touch one
two:
	touch two
three:
	touch three

clean:
	rm -f one two three
all: f1.o f2.o

# 这里的$@代表的是每一个target
f1.o f2.o:
	echo $@
# Equivalent to:
# f1.o:
#	 echo f1.o
# f2.o:
#	 echo f2.o
<targets> : <normal-prerequisites> | <order-only-prerequisites>
[tab]  <commands>

只有第一次构造 targets 时,才会使用 order-only-prerequisites。后面即使 order-only-prerequisites 发生改变,也不会重新构造 targets。只有 normal-prerequisites 中的文件发生改变时,才会重新构造 targets。这里,符号 “|” 后面的 prerequisites 就是 order-only-prerequisites

通过order-only-prerequisites可以帮忙预先创建目录和准备一些前置的文件,但这些条件即使后面发生了变化也不用触发target重新生成。下面这个例子就通过了order-only-prerequisites来创建目录,后面即使目录发生变化(目录内的内容发生变化)也不再导致target重新创建

BUILDDIR:=build

all: $(BUILDDIR)/test.o
clean:
    rm -rf $(BUILDDIR)

$(BUILDDIR):
    mkdir -p $(@)

$(BUILDDIR)/%.o: %.c | $(BUILDDIR)
		gcc -o $@ -c $<

Variables & Wildcards

=的定义变量,不会在定义的时候展开,而是在使用的使用展开,而:=则是定义的时候展开、?=只有变量没有定义的时候才会设置。

files := file1 file2
some_file: $(files)
	echo "Look at this variable: " $(files)
	touch some_file
# Recursive variable. This will print "later" below
# 在执行的时候才会展开later_variable
one = one ${later_variable}
# Simply expanded variable. This will not print "later" below
# later_variable这里还没有定义,因此是空
two := two ${later_variable}

later_variable = later

all: 
	echo $(one)
	echo $(two)