基本形式
target: prerequisites(also can be targets)
command
target可以为文件名,也可以为一个随意的字符串,make默认执行第一个有效target
执行逻辑:
- 检查前置条件,并达成所有前置条件
- 执行所有的command
扩展形式(可有部份文件不触发make)
target: prerequisites(also can be targets)|prerequisites(changes will not remake)
command
匹配模式
target:target-pattern:prereq-patterns:
command
objs:=a.o b.o
all:$(objs) #
$(objs):%.o:%.c
cc -c $< -o $@
.PHONY:clean
clean:
rm *.o
a.o b.o:%.o:%.c #只会生成a.o
cc -c $< -o $@
.PHONY:clean
clean:
rm *.o
双冒号模式(可存在多个相同目标,每个目标由不同的依赖触发)
test: a.c
cc -c $< -o a.o
test: b.c
cc -c $< -o b.o
会有警告并只执行后者
test:: a.c
cc -c $< -o a.o
test:: b.c
cc -c $< -o b.o
打印一个 hello
test:
echo hello
使用@可以不回显执行的命令
test:
@echo hello
make支持的变量仅有字符串类型
定义方式
- = = =,运行时展开,可使用先于声明
- : = := :=,编译时展开
- ? = ?= ?=,条件定义
- d e f i n e define define,多行变量
变量定义1
运行时展开变量,被读入的变量如果是引用其它的变量,则直到其被使用时,
才对其进行展开,这种变量使用
=
=
= 号赋值。
var1=$(val2)
val2=$(val3)
val3="hello "world
test:
@echo $(var1)
变量定义2
编译时展开变量,使用符号
:
=
:=
:= 。
无法使用在该变量定义的代码前无定义的变量。
var1:=1
var2:=$(var1)2"3"
test:
@echo $(var2)
变量定义3
多行变量
define var
echo foo
echo hello
endef
test:
$(var)
类似程序中的局部变量
var=fuck
all:test
echo $(var)
test:var=hello
test:
echo ${var}
模式匹配版本
var=fuck
%haha:var=hahafuck
all:test ahaha fuckhaha
test:
echo $(var)
ahaha:
echo $(var)
fuckhaha:
echo $(var)
字符串末位替换
写法1
var2:=123456
var1:=$(var2:456=abc)
test:
@echo $(var1)
写法2
var2:=123456
var1:=$(var2:%456=%abc)
test:
@echo $(var1)
写法3
var2:=123456
var1:=$(var2:%456=%abc)
test:
@echo $(patsubst %456,%abc,$(var2))
预定义变量
$@:
注意,模式匹配的单个目标会展开成多个目标
test:atest btest
@echo test
%test:
@echo $@
test fuck:
@echo $@
条件判断
- ifdef,ifndef,ifeq,ifneq,else,endif
var=fuck
test:
ifeq ($(var),fuck)
echo yes
else
echo no
endif
echo fuck
注意if表示不为空取后者,没有与else endif配合
var=cd
test:
echo $(if $(var),${var},c)
循环
test:
echo $(foreach i,a b c d, $(i)hello)
函数
注意,使用call
var=$(2)$(1)
test:
echo $(call var,a ,b)
listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
$(wildcard $(addsuffix $(SLASH)*,$(1))))
test:
echo $(call listf,*.c)
不展开变量的函数
var=${hello}
hello=fuck
test:
echo $(var)
echo $(value var)
eval函数
- 基础用法
将变量定义的字符串转成makefile代码
$(eval var=hello)
all:
@echo $(var)
- 将多行文本转化成makefile代码
define macrotarget
all:
@echo macrotarget
endef
$(eval $(call macrotarget))
- 配合makefile变量和macro参数使用
var=var
define mfunc
$(1):
@echo $(var)
@echo $(1)
endef
$(eval $(call mfunc,hello))
- 二次展开
var1=var2
var2=var3
define two
$${${var1}}=test
endef
$(info $(call two))
$(eval $(call two))
all:
echo ${var3}
var2=var3
$(eval ${var2}=test)
all:
echo ${var3}
预定义的文本处理函数
调用格式$
(
f
u
n
c
t
i
o
n
,
p
a
r
a
m
s
)
(function,params)
(function,params)
局部替换函数
全局替换
$(subst FROM,TO,TEXT) #将text中的FROM换成TO
var=fuckfuck
test:
echo $(subst fuck,hello,${var})
尾部替换
var=a.c.c #针对变量的简洁写法
test:
echo $(patsubst %.c,%.o,a.c.c)
echo $(var:.c=.o) #针对变量的简洁写法
空格去除
var= a b c
test:
echo $(strip $(var))
查找匹配字符串,成功返回该字符串,否则空串
test:
echo $(findstring abc,abcd)
echo $(findstring abc,abdc)
过滤掉不符合模式的字符串
test:
echo $(filter %.c,a.c b.c b.c.c a.o)
反向过滤
test:
echo $(filter-out %.c,a.c b.c b.c.c a.o)
排序(首字母升序)
test:
echo $(sort a bc cb A B C)
取单词
test:
echo $(word 1, a bc cb A B C)
取多个单词
test:
echo $(wordlist 1,3, a bc cb A B C)
计算有多少个单词
test:
echo $(words 1,3, a bc cb A B C)
预定义文件处理函数
取目录
test:
echo $(dir /mnt/a/a.c /test/a.a)
取文件名
test:
echo $(notdir /mnt/a/a.c a.c)
取文件名后缀(没后缀则忽略,不产生空串)
test:
echo $(suffix /mnt/a/a.c b a.c)
取文件名(不包括后缀)
test:
echo $(basename /mnt/a/a.c b a.c)
给文件添加后缀
test:
echo $(addsuffix .haha, /mnt/a/a.c b a.c)
给文件添加前缀(注意文件名不要包括目录)
test:
echo $(addprefix hello_, /mnt/a/a.c b a.c)
文件名拼接
test:
echo $(join a b,.a .b)
列出当前目录下匹配成功的文件名集合
test:
echo $(wildcard *.c)
自动化变量
空目标默认不是最新的
$@
显示为test
test:
echo $@
$%
test(hello):
echo $@ $%
$<
test(hello):r1 r2 r3
echo $<
r1 r2 r3:
? 假设 a . o 存在, b . o 不存在, ? 假设a.o存在,b.o不存在, ?假设a.o存在,b.o不存在,?=b.o
ab.a:a.o b.o
echo $?
ar rcs ab.a a.o b.o
$^ 表示所有依赖
test:c d e f
echo $^
a b c d:
二次扩展
.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o
all: main lib
main lib: $$($$@_OBJS)
echo $^
main.o try.o test.o:
lib.o api.o: