基本概念
makefile 一般采用从上而下(top-down)的结构,所以默认会更新
最上层的工作目标(通常叫all
),下层的目标用来让上层工作目标保持在最新状态。例如用来删除无用的临时文件的clean
工作目标应该放在最下层。
target1 target2 target3 : prerequisite1 prerequisite2
command1
command2
command3
- 每个命令必须以制表符
[Tab]
开头 #
为注释符\
为延续行符
规则
通配符
~
当前用户主目录.
匹配任意字符*
匹配任意数量?
[...]
字符集[^...]
字符集的补集
假想目标
.PHONY 显式指定为假想目标,告诉 make 这不是一个目录,即使有这个目录存在.
.PHONY: clean
clean:
rm -f *.o xxxxx
标准的假想工作目标
all
执行编译应用程序的所有工作install
从已编译的二进制文件进行应用程序的安装clean
清理distclean
删除编译过程中除了可执行文件外的所有文件TAGS
建立可供编辑器使用的标记列表info
从 Texinfo 源代码来创建 GNU info 文件check
执行与应用程序相关的任何测试
补充说明:当不带参数运行 make
时,默认运行 all
目标
变量
# 定义变量
variable-name = xxxxxxx
# 扩展变量
${variable-name}
# 或
$(variable-name)
自动变量(automatic variable)
由 make 设定,可作为工作目标或元素.
$@
工作目标的文件名$%
档案文件成员结构的文件名元素.$<
第一个必要(需求)文件的文件名$?
时间戳在工作目标后的所有必要条件,以空格分割$^
所有必要条件的文件名,空格分割,自动去重$+
同$^
但包含重复文件名(比如,传给连接器 linker 时有意义)$*
工作目标的主文件名(一个文件名由主文件名 stem 和 后缀名 suffix 组成) 注: 若工作目标是 foo.a(bar.o), 则$%
是 bar.o,$@
是 foo.a,$*
是 foo
用 VPATH 和 vpath 来查找文件
可以用 vpath
来告诉 make
到不同目录去查找源文件.
vpath pattern directory-list
除非明确指出, make
只会在当前目录下寻找工作目标和必要条件.
下例中的源文件 *.c
均位于 src 目录下,头文件 *.h
均在 include
目录下:
CPPFLAGS = -I include
VPATH = src include
count_words: count_words.o counter.o lexer.o -lf1
gcc $^ -o $@
count_words.o: count_words.c include/counter.h
gcc --c $< -o $@
counter.o: counter.c include/counter.h include/lexer.h
gcc -c $< -o $@
lexer.o: lexer.c include/lexer.h
gcc -c $< -o $@
lexer.c: lexer.l
flex -t $< > $@
更安全的方式是,用通配符形式指定相应目录下用到的文件形式.
vpath %.l %.c src
vpath %.h include
注: -lfl
make会去标准程序库找到 libfl.a
模式规则
首先,所有C编译器会假设,文件若是以 .c 为扩展名,其所包含的就是C源代码,把扩展名从 .c 替换成 .o (对 WIN 的一些编译器来说是 .obj)就可以得到目标文件的文件名. make可以使用这些内置规则,makefile就变为:
VPATH = src include
CPPFLAGS = -I include
count_words: counter.o lexer.o -lfl
count_words.o: counter.h
counter.o: conuter.h lexer.h
lexer.o: lexer.h
上述文件之所以能用,是因为 make 中内置了三条规则:
- 如何从一个 .c 编译出一个 .o
%.o %.c $(COMPILE.c) $(OUTPUT_OPTION) $<
- 如何冲一个 .l 产生一个 .c
%.c %.l @$(RM) $@ $(LEX.l) $< > $@
- 如何冲一个 .c 产生一个不带扩展名的,可执行文件
%: %.c $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
可以用 make --print-data-base
命令查看所有的默认规则
模式规则中的 %
大体上相当于 shell 中的 *
但只能出现一次
例如:
%: %.mod
$(COMPILE.mod) -o $@ -e $@ $^
%: %.cpp
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
%: %.sh
cat $< >$@
chmod a+x $@