Makefile笔记
Makefile笔记
Makefile为make工具提供一系列规则,是Linux下变成的有效生产力工具。make在后面不加参数时,会自动寻找Makefile,后面不加目标文件,默认生成第一条规则定义的文件。
文件格式
Makefile的每一条规则的形式如下:
<target> : <prerequisities>
[tab] <command>
每条规则说明:构建(build)目标的前置条件是什么,如何构建。其中,“目标”是必需的,“前置条件”和“命令”至少有一个。
target
target通常是文件名,指明要构建的对象。
还有一种用法,使用“伪目标”来执行操作
.PHONY: clean #声明clean是伪目标
clean:
rm *.o #清除.o文件的操作
prerequisites
前置条件通常是一组文件名,之间用空格分割。
指定了“目标”是否重建的判别标准:前置文件有过更新(前置文件的last-modification时间戳比目标文件的时间戳新),目标文件就需要重建。
如果前置文件没有,会报错停止。
result.txt: source.txt
cp source.txt result.txt
commands
命令表示如何更新目标文件,由一行或多行的shell命令组成,它是构建“目标”的具体指令,运行结果通常是生成目标文件。
基本语法
注释
和shell一样,注释是用#号
回声
正常情况下,make会打印每条命令,然后执行,可以在命令之前加上@可以关闭回声(echoing)
.PHONY: test
test:
@echo "hello" #@号关闭了回声
只输出hello
通配符
Makefile中的通配符与bash一致,主要是?和*
模式匹配
使用%方便处理大量同类文件
%.o : %.c
#等价于
#f1.o:f1.c
#f2.o:f2.c
#......
变量
Makefile允许自定义变量
v1 = Hello World
v2 = $(v1)
test:
@echo $(v2) #变量要被包裹在$()中
@echo $$HOME #调用shell变量时,要多加一个$进行转义
赋值方式有多种
VARIABLE = value
# 在执行时扩展,允许递归扩展。
VARIABLE := value
# 在定义时扩展。
VARIABLE ?= value
# 只有在该变量为空时才设置值。
VARIABLE += value
# 将值追加到变量的尾端。
Makefile还有内置变量
比如,$(CC) 指向当前使用的编译器,$(MAKE) 指向当前使用的Make工具。这主要是为了跨平台的兼容性。
自动变量
(1)$@指代当前正在构建的目标
a.txt:
@touch $@ #指代正在构建的a.txt
#等价于
#a.txt:
# @touch a.txt
(2) $<指代第一个前置条件
a.txt: b.txt c.txt
cp $< $@ #这里$<指代b.txt
#等价于
#a.txt: b.txt c.txt
# cp b.txt a.txt
(3) $?指代比目标更新的所有前置条件,中间用空格隔开。比如,规则为t: p1 p2,其中p2的时间戳比t新,$?就指代p2
(4) $^ 指代所有前置条件,之间以空格分隔。比如,规则为t: p1 p2,那么$^就指代p1 p2
(5) $* 指代匹配符%匹配的部分,比如%匹配f1.txt中的f1,$*就表示 f1
(6) $(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名。
(7)$(<D) 和$(<F) 分别指向 $< 的目录名和文件名。
例子
dest/%.txt: src/%.txt
@[ -d dest ] || mkdir dest
cp $< $@
上面代码将src目录下的txt文件,拷贝到 dest 目录下。首先判断dest目录是否存在,如果不存在就新建,然后,$<指代前置文件(src/%.txt),$@指代目标文件(dest/%.txt)。
判断和循环
判断训话的语法和bash一致
#if语句
ifeq ($(CC),gcc)
libs="gcc"
else
libs="not gcc"
endif
testIf:
@echo $(libs)
#循环
LIST = one two three
#不同行makefile中的shell属于不同进程,在同一行用;分隔可以在同一个shell内执行,
#"\"可以连接多行
all:
@for i in $(LIST); \
do \
echo $$i; \
done
Makefile函数
函数调用格式
$(function arguments)
常用函数举例
(1) shell
可以执行shell命令
test:
@echo $(shell pwd)
(2)wildcard
可以使用bash的通配符
test:
@echo $(wildcard dir/*.txt)
(3) subst
文本替换函数
#格式
$(subst from,to,text)
comma = ","
#空变量
empty =
#空格需要用空变量作为标识符
space = $(empty) $(empty)
foo = "a b c"
#不能有多余空格
bar = $(subst $(space),$(comma),$(foo))
test:
@echo $(bar)
(4) patsubst
用于模式匹配的替换
#格式
$(patsubst pattern,replacement,text)
#将文件名"x.c.c bar.c",替换成"x.c.o bar.o"
$(patsubst %.c,%.o,x.c.c bar.c)
(5) OUTPUT
替换后缀名
min: $(OUTPUT:.js=.min.js)
编译C语言项目例子
edit : main.o kbd.o command.o display.o
cc -o edit main.o kbd.o command.o display.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h
cc -c display.c
clean :
rm edit main.o kbd.o command.o display.o
.PHONY: edit clean