1. Makefile引入
简单编译C文件时一般用的gcc:gcc -o test a.c b.c
。
但是当项目变得十分庞大时,逐个文件编译,效率极低。这时候必须引入Makefile作为编译管理。
当项目设计诸多模块,层级目录复杂时,常规做法是在每个子目录中放一个子Makefile,在顶层目录放一个总控Makefile。执行这个Makefile,即可完成整个项目的编译。
2. 规则
makefile的核心是规则,很简单
target1 : prerequisite1 prerequisite2
command prerequisite1 -o target1
其中:
target1: 要生成的目标
prerequisite :生成目标所需的条件,即依赖
command :生成目标所需的命令
更多隐含规则:make的隐含规则数据库可以用make -p
命令打印
3. 标记
-
#
注释 -
%.o
通配符 -
$@
目标文件 -
$<
第1个依赖文件 -
$^
所有依赖文件main : main.o stack.o maze.o gcc -o $@ $^ main.o: main.h stack.h maze.h stack.o: stack.h main.h maze.o: maze.h main.h main.o: main.c gcc -c $< stack.o: stack.c gcc -c stack.c maze.o: maze.c gcc -c maze.c
-
.PHONY
伪目标.PHONY: clean clean: # -代表即使rm执行失败,也会继续删除后续的*.o, 而不会就此中断 # -一般用在rm/mkdir。因为则2个命令可能会失败 -rm *.o # 打印出信息 @echo clean all objfiles
4. 变量
makefile中定义变量:v = xxx
。当需要引用变量v时:$(v)
。这里讨论如下运算符:=, :=, ?=, +=
-
:=
即时变量,在定义时即确定# desc: 代表遇到变量定义立即展开 x := foo y := $(x) bar # 当读到$(b)时b还未定义,则展开为空值(什么也没有)。即:$(a) -> 空格+bar a := $(b) bar b := hello tar2: @echo "-$(a)-"
-
=
延时变量,值使用到时才确定# desc: 当makefile读到这行时,不会立即展开$(bar) # 而是当读到@echo $(foo)是再展开$(foo),继而展开$(bar) foo = $(bar) bar = Huh? tar1: @echo $(foo)
-
?=
如果变量前面未定义过,则?=相当于=。否则什么也不做# desc: 如果foo前面未定义过,则?=相当于=。否则什么也不做 foo ?= I am a fool tar3: @echo "-$(foo)-"
-
+=
附加, 它是即时变量还是延时变量取决于前面的定义# desc:给变量追加值。 # 如果obj是=定义的,则+=仍保持=的特性; # 如果obj是:=定义的,则+=保持:=的特性 obj := main.o obj += $(fo) fo = fo.o bar.o tar4: @echo "-$(obj)-"
4. 函数
$(foreach var,list,text)
把参数- 中的单词逐一取出放到参数所指定的变量中,然后再执行< text>所包含的表达式
$(filter pattern...,text)
在text中取出符合patten格式的值$(filter-out pattern...,text)
在text中取出不符合patten格式的值$(wildcard pattern)
pattern定义了文件名的格式,wildcard取出其中存在的文件$(patsubst pattern,replacement,$(var))
从列表中取出每一个值,如果符合pattern,则替换为replacement