GNU Make
相关链接: isaac/Makefile
我曾经十分瞧不起 Make。因为乍一看正常的 Makefile,这不就是给 shell 脚本加几个标签,然后运行吗?
直到自己稍微会用一些了,才感叹到 Make 的强大。
Do not ask whether a statement is true until you know what it means.
— Erret Bishop
Make 的基本用法中构造的对象是文件。 通过以下方式指定源文件和输出文件:
file.out: file.c
gcc file.c -o file.out
这告诉了 Make 输出文件为 a.out
,它由一个源文件 a.c
来构建。这样 Make 只会在 a.out
不存在或 a.c
有更新时运行 gcc a.c -o a.out
。
这样的依赖也可以是多层的:
file.out: file.o
gcc file.o -o file.out
file.o: file.S
gcc -c file.S -o file.o
file.S: file.c
gcc file.c -S -o file.S
$: make file.out
gcc file.c -S -o file.S
gcc -c file.S -o file.o
gcc file.o -o file.out
$: touch file.o # 只更新了 file.o
$: make file.out
gcc file.o -o file.out
关键符号们
$
:首先当然就是它了,$
再加上一个字符就构成了为数众多的其他关键符号。有些关键符号需要用到多于一个字符,那么就用括号包裹起来,以这种形式出现 $()
。以 $()
包裹着还表示这是一个 Makefile 里的变量,虽然它和 shell 里面的变量长得很像,不过请把他们区分开。如果你仅仅是想在 Makefile 中表示一个普普通通的(字面上的) $
,请使用 $$
来转义。
%
:目标和依赖中可以使用的通配符。依赖中通配符表示的实际值,会和你指定的目标匹配到的那一段保持一致。# Okay: %.out: %.c # Okay: gcc $< -o $@ # Bad: gcc %.c -o %.out
$@
:目标文件,可在 rule 的内容(shell 脚本)中使用。$<
:“输入” 文件,即依赖文件。可在 rule 的内容中使用。$^
:所有 “输入” 文件。$*
:%
匹配到的那部分,可在内容中使用。
函数
$(strip string)
移除字符串首尾的空格。
$(wildcard filename)
返回匹配的文件名。
$(firstword string)
$(lastword string)
如名。
一些坑
匹配
Make 支持通配符。当一个文件同时满足两个规则的通配符时,它会优先匹配最接近的那个。
%.js:
blabla-1
%.bundle.js:
blabla-2
$: make app.bundle.js
blabla-2
空规则
如果一个规则的命令为空,Make 会尝试寻找其他匹配这个文件名的规则执行。然后就可能会出错。
# 命令为空!
dist/%: generate
.PHONY: generate
generate:
blabla-1
%.html:
blabla-2 > $@
$: make dist/a.html
# Expected: blabla-1
blabla-2 > dist/a.html
“变量”
嗯,Makefile 中的变量不是实际意义上的变量。Make 会事先把 Makefile 运行一遍,将变量计算出结果后再传入 shell 运行。