跳转至

Makefile

Makefile

基础概念

Makefile由若干条规则(Rule)构成,每一条规则指出一个目标文件(Target),若干依赖文件(prerequisites),以及生成目标文件的命令。

执行make 参数命令会构建参数对应的规则,若没有参数则默认执行第一条规则。

一条规则格式为目标文件: 依赖文件1 依赖文件2 ...,紧接着,以Tab开头的是命令,用来生成目标文件。

Makefile会自动判断依赖并打印执行命令。

Makefile最大的优势就是增量更新,它会根据依赖文件与目标文件的修改时间来自动判断是否更新

规则详解

伪目标

我们会希望通过一些规则丰富操作,如清理中间文件。

此时要避免规则被视为目标文件,可引入伪目标标识Phony Target

.PHONY: clean
clean:
    rm -f m.txt
    rm -f x.txt

命令执行

make针对每条命令,都会创建一个独立的Shell环境

为了让命令在同一环境执行,需要连接为一行,采用;分割命令, \换行以便于浏览

;可以换为&&,好处是某条命令执行失败后,后续命令不会继续执行

cd_ok:
    pwd; \
    cd ..; \        
    pwd           

默认情况下,make会打印出它执行的每一条命令,并且在命令出错后,打印错误并退出

我们可以通过@来取消命令的打印,用-来忽视报错并继续执行

    @echo 'not display' 
    -rm zzz.txt

对于重复的命令,我们还可以定义命令包,以define开始,以endef结束

随后可以用$(包名)作为命令。(亦可以用于多行变量的命名)

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

变量使用

Makefile,中可以命名变量(一般大写)来代替重用内容,变量定义用变量名 = 值

变量命名还可以使用make的模式替换的内置语法,如OBJS = $(SRCS:.c=.o)

同时我们可以使用Makefile中的自有变量:

  • $(CC): 表示C编译器的名字

  • $@:表示目标文件

  • $^:表示所有依赖文件

  • $<:表示第一个依赖项

  • $*:表示目标文件名的主体部分(不包括扩展名)

  • $(*D):表示目标文件主体部分的目录。如果目标文件主体是 dir/target,则 $(*D) 为 dir。

  • $(*F):表示目标文件主体部分的文件名。如果目标文件主体是 dir/target,则 $(*F) 为 target。

规则进阶

模式规则

Makefile中,我们可以自定义模式规则,make会依据规则模式自动匹配,如:

# 模式匹配规则:当make需要目标 xyz.o 时,自动生成一条 xyz.o: xyz.c 规则:
%.o: %.c    #`%`是一个通配符,表示任意数量的字符
    @echo 'compiling $<...'
    cc -c -o $@ $<

%是一个通配符,表示任意数量的字符

自动生成依赖

可以通过Makefile中的内置函数帮助依赖生成

  • wildcard

    语法如,$(wildcard pattern),

    用于匹配文件模式并返回符合模式的文件列表。

  • patsubst

    语法如,$(patsubst pattern,replacement,text)

    用于字符串替换。

  • findstring

    语法如$(findstring a,a b c) #返回a

    如果 find 是 in 的子串,则返回 find