Make是用于编译连接的构建工具,运行时将会依赖于Makefile来确定如何构建整个工程。Makefile类似于编译构建规则的集合。
1. Makefile基本规则
1.1 基本格式
<target>:<prerequisties...>
<commands>
target:
- 必须有,<target>为构建rules的名字;
- 执行make <target>时,将会按该target制定的规则来进行编译构建目标,当只执行make时,默认先执行Makefile中定义的第一个target;
prerequisties:
- 不是必须存在的,可理解为编译构建的输入文件,在执行该target前,需先确认prerequisties是否存在,只有存在时,才会继续按target编译构建,且当已经编译构建过,再次执行make时,只有prerequisties发生改变时才会再次重新编译构建;
commands:
- 不是必须存在的,但和prerequisties必须存在一个;
1.2 基本语法
-
print:@
按Makefile规则运行时,默认会先打印出执行的规则或命令,即使是那些注释(#)也会被打印输出,再去执行;
若不想输出这些打印,可在前面加上@;
-
变量引用
shell变量:
每行命令在shell是单独调用运行的,因此,如果在某行的shell命令中定义了一个变量,是无法在下一行shell命令中引用该变量的。另外,若想引用shell变量,需用双$来进行引用。因为每行的第一个$会被自动解析掉,第二个$才会被当做shell变量。
@#错误target示例:
var-lost:
@export foo=bar
@echo "foo=[$$foo]"
@#运行结果: foo=[]
@#正确示例:
var-kept:
@export foo=bar; \
echo "foo=[$$foo]"
@#运行结果: foo=[bar]
Makefile变量:
用$(val)来指代Makefile中定义的val变量;
- $(MAKE): 指代当前的make,如$(MAKE) target1相当于在shell中执行make target1;
1.3 特殊符号及应用
特殊符号
make可用通配符来构建一个通用的规则,以实现对大量文件的各自独立编译构建。
- $@ :当前执行的target;
- $< :第一个prerequisties;
- $^ :所有的prerequisties;
- $? :所有发生改变(比target更新)的prerequisties;
- $$ :貌似就是指代$;
- % :类似于*的占位符;
- $* :指代%匹配的部分;
- := :Makefile中的等号: 如 a := $(shell echo src/{00..99}.txt)
另外,D与上述特殊符结合,指代其目录,F与上述特殊符结合,指代其文件部分。如:
@#假设$@: src/input.c
$(@D) ##指代src
$(@F) ##指代input.c
批量编译
@#生成00~99.txt并将其存在srcfiles变量中
@#用wildcard可避免某个文件已存在的情况
srcfiles := $(shell echo src/{00..99}.txt)
@#srcfiles := $(wildcard src/*.txt)
@#模块2
src/%.txt:
[ -d src ] || mkdir src
echo $* > $@
source:$(srcfiles)
运行结果:将生成dst/00.txt~99.txt,其内容为其名字
make source
[ -d src ] || mkdir src
echo 00 > src/00.txt
[ -d src ] || mkdir src
echo 01 > src/01.txt
[ -d src ] || mkdir src
echo 02 > src/02.txt
[ -d src ] || mkdir src
echo 03 > src/03.txt
[ -d src ] || mkdir src
echo 04 > src/04.txt
其中source target是一个phony target,与".PHONY:"功能一致。
它依赖于保存在srcfiles变量中的所有文件,由于$(srcfiles)为:src/00.txt src/01.txt src/02.txt ... src/99.txt, 所以make source时,相当于依次make src/00.txt make src/01.txt ... make src/99.txt, 相当于依次执行模块2.