makefile的重要函数和通配符
Makefile中wildcard的介绍
在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN...) 。在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。需要注意的是:这种情况下规则中通配符的展开和上一小节匹配通配符的区别。
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。复杂一些用法;可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。因此在一个目录下可以使用如下内容的Makefile来将工作目录下的所有的.c文件进行编译并最后连接成为一个可执行文件:
#sample Makefile
objects := $(patsubst %.c,%.o,$(wildcard *.c))
foo : $(objects)
cc -o foo $(objects)
这里我们使用了make的隐含规则来编译.c的源文件。对变量的赋值也用到了一个特殊的符号(:=)。
1、wildcard : 扩展通配符
2、notdir : 去除路径
3、patsubst :替换通配符
例子:
建立一个测试目录,在测试目录下建立一个名为sub的子目录
$ mkdir test
$ cd test
$ mkdir sub
在test下,建立a.c和b.c2个文件,在sub目录下,建立sa.c和sb.c2 个文件
建立一个简单的Makefile
src=$(wildcard *.c ./sub/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c,%.o,$(dir) )
all:
@echo $(src)
@echo $(dir)
@echo $(obj)
@echo "end"
执行结果分析:
第一行输出:
a.c b.c ./sub/sa.c ./sub/sb.c
wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。
第二行输出:
a.c b.c sa.c sb.c
notdir把展开的文件去除掉路径信息
第行输出:
a.o b.o sa.o sb.o
在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
任何输出。
或者可以使用
obj=$(dir:%.c=%.o)
效果也是一样的。
这里用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。
它的标准格式是
$(var:a=b) 或 ${var:a=b}
它的含义是把变量var中的每一个值结尾用b替换掉a
=========================================================================================
此两者均为通配符,但更准确的讲,%为Makefile规则通配符,一般用于规则描述,如
%.o:%c
$(CC) $< -o $@
表示所的目标文件及其依赖文件,或者
$(filter %.c ,SOURCES)
此处SOURCES表示包含.c .cc .cpp等多类型源文件,该过滤器函数将c文件过滤出来,而%.c即为此过滤器规则。
通配符*则不具备上述功能。尤其是在Makefile,当变量定义或者函数调用时,该通配符的展开功能就失效了,即不能正常使用了,此时需要借助wildcard函数。二者应用范围不同。
=============================================================================================================
.PHONY :$(ModuleLib) all clean
all :$(target)
$(target) :$(ModuleLib) $(Srcs_obj) $(DependLib)
@echo Making target...
$(CC) -lpthread -lrt -lgcov $(LDFLAGS) -o $@ -Wl,--start-group $^ -Wl,--end-group
$(ModuleLib):
$(RM) $(ModuleLib)
cd $(ModuleDir)/make && ./mkfppall.sh gtest
%.co :%.c
@echo Compiling Src file:[$(notdir $<)]...
$(CC) $(CXXFLAGS) -c $< -o $@
clean :
$(RM) $(Srcs_obj) $(Srcs_gcno) $(app)
makefile中的伪目标:
A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request. There are two reasons to use a phony target: to avoid a conflict with a file of the same name, and to improve performance.
在本例中,$(ModuleLib)由于没有依赖文件,因此,在普通的make中不会执行命令(因为没有文件比它新),现在将其作为伪目标之一,因为
伪目标gcc不当做真正的文件,因此不会去比较目标新旧,其命令总是能被执行。
https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
伪目标总是能够被执行。
如果一个目标不存在,就相当于隐式的伪目标,它的命令也总是可以跑一边。
makefile:
1、如果目标不存在,执行命令。(包括依赖和命令)
2、如果目标存在,依赖文件有更新(依赖文件是递归的,找依赖的依赖,如果有更新,就更新)。执行命令。
3、如果目标存在,且依赖没有更新,(递归的,包括依赖的依赖。。。),不更新,不执行命令。
============================================================================================================
%和*的区别:
此两者均为通配符,但更准确的讲,%为Makefile规则通配符,一般用于规则描述,如
%.o:%c
$(CC) $< -o $@
表示所的目标文件及其依赖文件,或者
$(filter %.c ,SOURCES)
此处SOURCES表示包含.c .cc .cpp等多类型源文件,该过滤器函数将c文件过滤出来,而%.c即为此过滤器规则。
通配符*则不具备上述功能。尤其是在Makefile,当变量定义或者函数调用时,该通配符的展开功能就失效了,即不能正常使用了,此时需要借助wildcard函数。二者应用范围不同。
=====================================================================================================================
cd 命令在makefile里面只对当前行有用。
比如你在/opt下执行makefile
如果我要tar开一个包在 /lib下
cd /lib
tar -xvf xxxx.tar
结果只会将这个tar包在执行makefile的当前目录下/opt解包
正确写法是:
cd /lib && tar -xvf xxxx.tar 或者 cd /lib; tar -xvf xxxx.tar