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


posted @ 2017-11-29 21:46  elseliving的记录  阅读(3839)  评论(0编辑  收藏  举报