makefile语法¶
基本写法¶
需要注意的是, 每一行commands在一个单独的shell进程中,这些shell之间没有任何继承关系
<target> : <prerequisites>
[tab] <commands>
比如下面的例子的运行结果为:MY_PATH=[]
mytarget:
export MY_PATH=aaabbbccc
echo "MY_PATH=[$$MY_PATH]"
下面的例子的运行结果为:MY_PATH=[aaabbbccc]
mytarget:
export MY_PATH=aaabbbccc; \
echo "MY_PATH=[$$MY_PATH]"
思考一下, 为什么要写成MY_PATH, (MY_PATH) 能打印出来吗?这里可以参考如下文章的解释,实质上makefile会先去解释第一个,而shell会去解释第二个,而shell会去解释第二个,而shell会去解释第二个,而shell会去解释第二个,如果只有一个,如果只有一个,而shell会去解释第二个,而shell会去解释第二个,而shell会去解释第二个,而shell会去解释第二个,如果只有一个,如果只有一个, make 会因为找不到变量MY_PATH而终止,因为MY_PATH是定义在shell中的。
https://blog.csdn.net/darennet/article/details/8185881
基本语法¶
直接式变量赋值与递归式变量赋值¶
# 递归式变量赋值,make会将整个makefile展开后,再决定变量的值
algo = gzip.o lzma.o
# 直接式变量赋值,变量的值决定于它在makefile中的位置
algo := gzip.o lzma.o
举个例子就能说明区别
_algo = gzip
algo := $(_algo)
_algo = lzma
test:
@echo "algo=$(algo)"
输出应该为gzip,也就是说在定义的时候就展开了
_algo = gzip
algo = $(_algo)
_algo = lzma
test:
@echo "algo=$(algo)"
输出应该为lzma,将整个makefile展开后才确定了_algo的值,进而确定了algo的值
打印回显¶
# 正常情况下make 会打印每一条命令然后再执行,使用@可以阻止回显
echo "hello world!"
@echo "hello world!"
其他赋值¶
只有在变量未被赋值时才赋值
# 条件赋值
algo ?= lzma
# 增量式赋值
algo += gzip
使用函数¶
return = $(functionname arg1, arg2, arg3...)
扩展通配符wildcard¶
# * 表示任意一个或多个字符
# ? 表示任意一个字符
# [...] [abc] 表示abc中任意一个字符匹配, [^abc]表示除abc意外的字符
# [0-9] 表示0~9任意一个数字
algo = $(wildcard *.c)
test:
@echo "algo=$(algo)"
假如在Makefile所在的目录下有lzma.c, gzip.c, bzip2.c, xz.c, lzo.c 那么algo会打印出所有的这些.c文件名称
匹配替代通配符patsubst¶
# % 为模式字符
algo = $(patsubst %.c,%.o,$(wildcard *.c))
test:
@echo "algo = $(algo)"
去除路径notdir¶
OBJS = /usr/opt/bin/algo.c
algo = $(notdir $(OBJS))
test:
@echo "algo = $(algo)"
运行结果
root@chlxy:# make
algo = algo.c
字符串替换subst¶
string_old = AAAAABBBBBCCCCC
string_new = $(subst A,a,$(string_old))
test:
@echo "new string is $(string_new)"
运行结果,其中需要注意,如果在上述A,a,后面加空格再加$(string_new)会导致输出中带有空格
root@chlxy:# make
new string is aaaaaBBBBBCCCCC
过滤函数filter¶
string_old = AAAAA.c BBBBB.o CCCCC.s
string_new = $(filter %.o, $(string_old))
test:
@echo "new string is $(string_new)"
运行结果
root@chlxy:# make
new string is BBBBB.o
循环函数 foreach¶
algos = lzma gzip lzo lz4 xz
algofiles = $(foreach algo, $(algos), $(algo).c)
test:
@echo "$(algofiles)"
运行结果
root@chlxy:# make
lzma.c gzip.c lzo.c lz4.c xz.c
显式运行shell¶
algos = $(shell ls)
test:
@echo "$(algos)"
运行结果
root@chlxy:# make
bzip2.c gzip.c lz4.c lzma.c lzo.c Makefile xz.c
运行控制 error 与 warning¶
ifndef ARCH
$(error should define ARCH...)
endif
ifndef PLAT
$(warning forget define PLAT ?)
endif
test:
@echo "this is a test"
运行结果
root@chlxy:# make
Makefile:3: *** should define ARCH...。 停止。
root@chlxy:# make ARCH=arm
Makefile:7: forget define PLAT ?
this is a test
root@chlxy:# make ARCH=arm PLAT=yes
this is a test
其他函数¶
# 函数太多,具体使用方法就不再一一举例了
# 将字符串升序排列,并去掉重复单词
sort
# 取单词函数
word
# 取字符串函数
wordlist
# 统计字符串中单词数目
words
# 取字符串的第一个单词,lastword同理取最后一个单词
firstword
# 取目录,包含指定文件的路径目录
dir
# 取前缀函数
basename
# 实现用户自定义函数的引用,$(call function arg1,arg2,...)
call
条件判断¶
# ifeq ifneq ifdef ifndef
ifeq ($(ARCH), arm)
MY_ARCH = ARCH_ARM
else ifeq ($(ARCH), arm64)
MY_ARCH = ARCH_ARM_64
else
MY_ARCH = unknown
endif
ifdef PLAT
MY_PLAT = nxp
else
MY_PLAT = unknown
endif
test:
@echo "MY_ARCH = $(MY_ARCH) MY_PLAT=$(MY_PLAT)"
运行结果
root@chlxy:# make ARCH=arm
MY_ARCH = ARCH_ARM MY_PLAT=unknown
root@chlxy:# make ARCH=arm PLAT=yes
MY_ARCH = ARCH_ARM MY_PLAT=nxp
root@chlxy:# make ARCH=arm64
MY_ARCH = ARCH_ARM_64 MY_PLAT=unknown