makefile学习总结

Make file学习总结



. make file有什么?


  1. Make file主要包含了五个东西,显示规则,隐晦规则,变量定义,文件指示和注释说明


1.1. 显示规则:说明了如何生成一个或多个目标文件

1.2. 隐晦规则:利用make 的自动推导功能,可以使我们可以粗糙简略地写make

1.3. 变量定义:类似C的宏

1.4. 文件指示:在一个makefile中引用另一个makefile,类似C中的include

根据某种情况指定makefile中的有效部分,类似C的预编译

定义一个多行的命令

1.5. 注释说明:和shell script中一样,使用#,不支持多行注释


注意:在makefile中,命令行,必须要用tab键开始


  1. Make file的引用


makefile中,使用include<file name>来引用其他的makefile,类似Cincludefilename可以是包含路径和通配符。

Make命令开始时,会找寻include中的makefile,并把文件安置在此位置。如果文件没有路径,就先会在当前目录寻找,没有找到的话,会提示警告信息。

include前面叫一个“-号,可以强制不显示警告信息


注意:include前面不可以使用tab键,可以使用空格。


  1. Makefile的工作方式


3.1. 读入makefile

3.2. 读入include中的makefile

3.3. 初始化文件的变量

3.4. 推导隐晦规则,并分析所有规则

3.5. 为所有的目标文件创建依赖关系

3.6. 根据依赖关系,确定那些文件要重新生成

3.7. 执行生成命令


1-5步为第一阶段,6-7步为第二阶段。在第一阶段中,如果定义的变量被使用,那么,make会把其展开在使用的位置。但make并不会完全马上展开,make会使用拖延战术,例如变量出现在依赖关系的规则中,那么仅当这条依赖决定要使用,变量才会在其内部展开。


  1. Make file的语法


  1. 规则的语法

主要包含有三块内容,目标(Targets),依赖和命令;目标和依赖(prerequisites)用冒号隔开,命令(Command)可以有两种方式,第一种:换一行,并且必须在命令前面有一个tab键(测试必须8个空格的长度),第二种方式:在依赖后面加上分号,可以直接连接命令


語法1


Targets : prerequisites

Command#命令要用一个TAB

語法2

Targets : prerequisites ; command#command前面用“;”


  1. 通配符的使用


如果想定义一系列类似的文件,我们很自然地就能想到使用通配符,在makefile中支持三种通配符。


  1. 1通配符的类型


Make 支持三种通配符:* [...] shell是相同的


22通配符的使用环境


通配符可以出现在以下两种场合:

        1. 规则的目标、依赖中,make在读取makefile时会将通配符展开

        2. 规则的命令中,由shell执行此命令时将通配符进行展开


23通配符的使用


通配符代替了一系列文件,如“*.c表示所有后缀名为“.c的文件,另外我们要注意的是,如果中有真实的“*字符,我们就需要使用转义字符“\,如“\*表示真实的“*字符,而不是任意长度的字符串。


*:表示任意多个字符

?:表示任意一个字符

[ ] :表示符合中括号中的字符


实例:

#当前工作目录下存在1.c ; 2.c ; test.c ; 1.h四个文件

Makefile文件的内容如下:

运行结果:



注意:objects= *.o ,表示通配符可以在变量中使用,但objects的值就是*.o,如果需要通配符在变量中展开,正确的写法是:objects= $( wildcard *.o ),下面学习wildcard方法时,会再次说道


  1. 文件搜索


在一些大的工程中,有大量的源文件,通常的做法是把这些文件分类,并存放在不同的目录中,所以当make需要去寻找文件的依赖关系时,可以在文件前加上路径,但最好的方法时把一个路径告诉make,让make自动去寻找。


VPATH就是完成这个功能的,如果没有指明这个变量,make只会在当前目录中去寻找依赖文件和目标文件。但如果定义了这个变量,那么make就会在当前目录找不到的情况下,到所指定的目录中去寻找文件。


3.1. 特殊变量“VPATH可以使make在当前目录找不到时,到其指定的地址去寻找


3.2. 多个地址

VPATH = src : ../headers #多个地址用号分隔

上面的定义指明了两个目录,“src和“../headersmake会按照这个顺序进行搜索


3.3. vpath关键字设置搜索路径(小写的,是makefile的关键字


另一种设置文件搜索路径的方法是使用vpath关键字,和VPATH变量很类似,但它可以指定不同的文件在不同的目录中,比较灵活。。

使用方法有三种:


vpath <pattern> <directories>#在指定的directories下,搜索符合pattern模式的文件。

vpath <pattern> #清除符合pattern的搜索目录

vpath #清除所有的目录


vpath使用方法中的<pattern>可以使用匹配符%%.h表示以.h结尾的文件,它指定了要搜索的文件集,<directories>则指定了<pattern>的文件集的搜索的目录,如:


vpath %.h ../headers(为了显示清楚,我中间多打了几个空格)


该语句表示,要求make../headers目录中搜索所有以“.h结尾的文件(如果这个文件在当前目录没有找到的话)


我们可以连续地使用vpath语句,以指定不同搜索路径。如果连续的vpath语句中出现了相同的<pattern>,或是被重复了的<patter>,那么make会按照vpath语句的先后顺序来执行搜索。


  1. 伪目标##特性:总是被执行


4.1. 伪目标不是一个文件,而是一个lable,只有通过显示的指明才能让其生效就是执行下面的command

4.2.伪目标命名不能与文件名相同

4.3. .PHONY显示的指明目标是一个伪目标,.PHONY是关键字


例如:

.PHONY clean

clean:

rm *.o


.PHONY为关键字,clean是伪目标,只要有这个声明,要运行clean这个目标,只能显示的指明才能生效,即使用makeclean命令来执行(执行make命令,是不会执行rm.o这个命令的)


    1. 伪目标可以作为依赖


伪目标一般没有依赖条件,但是我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”(如果没有指定的话,就是第一个目标),只要将其放在第一个。


.PHONY : cleanall cleanobjcleandiff


cleanall : cleanobj cleandiff

rm program


cleanobj :

rm *.o


cleandiff :

rm *.diff


我们可以使用makecleanall来清除以.o.diff结尾的文件和program文件,也可以用makecleanobj来清除.o结尾的文件或者用makecleandif来清除.diff结尾的文件。


cleanall : cleanobj cleandiff


就把cleanobjcleandif这两个伪目标作为cleanall伪目标的依赖条件。


  1. 多目标


bigoutput littleoutputtext.g

generate text.g -$( subst output, ,$@) > $@#subst 截取字符串

#$@表示目标的集合,就相当于一个数组

#$@可以依次取出数组中的数据,并执行命令

上语句相当于:

bigoutput : text.g

generate text.g -big >bigoutput

littleoutput : texts.g

generate text.g -little >littleoutput


其中,-$(subst output, ,$@)中的“$表示执行一个Makefile的函数,函数名为subset,后面的为参数。关于函数,后面会讲述。这个函数就是截取字符串的意思。

“$@表示目标的集合,也就是bigoutputlittleoutput就像一个数组。“$@依次取出目标,并执行命令。


  1. 静态模式

静态模式可以更加容易地定义多目标的规则,可以让规则变得更加的有弹性和灵活


语法:

<targets..>:<target-pattern>:<prereq-patterns…>

<commands>

….


targets:定义了一系列的目标文件,可以有通配符,是目标的一个集合

target-pattern:指明了targets的模式,也就是目标集模式

prereq-pattern:是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标定义


例如:

objects = foo.o bar.o

all: $(objects)

$(objects):%.o:%.c

gcc –c $< -o $@


上面的例子中,指明了目标从$(objects)中获取,%.o表明要所有以.o结尾的目标,也就是foo.obar.o,而依赖模式“%.c则取模式“%.o的“%部分,也就是foobar,并为其加上“.c的后缀,于是我们的依赖目标就是foo.cbar.c


  1. 自动变量


$@ : 工作目标的文件名

$< : 依赖目标中的第一个目标的文件名


目录中有两个文件,foo.cbar.c

例:

foo.o bar.o : foo.c bar.c

gcc –c $< -o $@

$@:表示一个文件集,里面有两个元素foo.obar.o(从文件中依次取出来使用)

$<:依赖目标中的第一个目标名称,即是foo.c。如果依赖目标是以模式(%.c)来定义的,(即foo.obar.o :%.c则表示符合模式的一系列的文件集,里面有两个文件foo.cbar.c(也是依次取出来的)


$% : 档案文件成员结构中的文件名元素

例如:

foo.a(bar.o) foo.cbar.o

commands

foo.a(bar.o)就是一个档案文件成员结构(函数库文件)$%就代表是bar.o,就是工作目标中小括号里面的文件;$@代表是foo.a

当工作目标不是一个档案文件成员时,$%则为空

函数库文件,unix下是.a结尾的文件


$^ : 所有依赖的文件名,以空格隔开,重复的已删除

:

有两个目录,一个目录中有文件:foo.cbar.c;另一个目录有文件:foo.c


foo.o : %.c

$^:表示所有依赖的文件名,即foo.cbar.c(两个文件名中间有一个空格),两个目录中依赖的文件有重复名字的(foo.c),但只能保留一个文件名


$+ : 如同$^,但包含重复的文件名


$* :工作目标的主文件名(一个文件名称是由两部分组成:主文件名和扩展名)

如果目标名为foo.c$*就是foo.c为后缀名


$? :时间戳在工作目标之后的所有必要条件(即依赖文件),并以空格隔开


一个大的项目中,第一次运行make时,会用掉很长的时间,这是因为所有的文件都需要进行编译,而以后修改一些文件后再运行make时,就会发现速度很快。这就是因为make会自动的去检查依赖和目标的时间戳,如果依赖的时间戳在目标之后,则表明依赖的文件被修改过,那么make就会再一次执行该command命令,以生成新的目标文件。否则就会直接跳过该命令。这种机制会在以后的编译中节省很多的时间。

:

bar.o : foo.c bar.c

command

如果我们应经修改了foo.c文件,在执行make时,make会根据时间戳判断出bar.o需要重新进行编译,即执行该command

$?就是代表时间戳在目标之后的依赖文件名,多个文件时,会以空格隔开。


  1. Make file的函数


Makefile的函数使用,和取变量一样,使用“$开始,括号中是函数名和参数,用空格隔开,参数用“,”隔开。


字符串处理函数


3.1. subst 字符串替换函数


old=1

new:=a

foo:=123123

bar:=$( subst $(old),$(new),$(foo))

#输出a23a23

#第一个参数$(old)为被替换字串,第二个参数$(new)为替换字串,

#第三个参数$(foo)为替换操作作用的字串即内容


结果:



3.2. patsubst 模式替换函数


$(patsubst pattern, replacement,text ) :::::::::::: $( patsubst %.c, %.o, $(XXXX) )


功能:搜索“TEXT以空格、TAB、回车、换行隔开的单词,将符合“pattern模式内容替换成“replacement,参数“pattern中可以使用匹配符“%


将所有以.c为结尾的字符换成以.o结尾

结果:


后缀时.c的都换成.o


3.3. strip去空格函数


$(strip string)


功能:去掉string中开头和结尾的空字符


Result:



3.4 findstring 查找字符串函数


$findstring<find>,<text>::$(findstring a, a b c) ==>> return a

:: $(findstring a, b c) ===>>return


功能:在text中查找find字符串,如找到returnfind,否则returnnull


object内容中查找foo.o,如果查到,返回foo.o,没有查到则返回空

结果:


如果没有这个文件,则返回空。


3.5 filter 过滤函数


$(filter <pattern>,<text>)

功能:以pattern模式过滤text字符串中的单词,保留符合pattern的单词


sources:=a.c b.c c.o d.z

$(filter %.c %.z, $(sources))

===>>return a.c b.c d.z可以看出c.o被过滤掉了


过滤object内容,保留以.c结尾的字符

Result:


输出符合.c的文件名


3.6 filter-out 反过滤函数


$(filter-out <pattern,...>,<text>)

功能:以pattern模式过滤text字符串中的单词,去除符合pattern的单词


Sources:=a.c b.c c.o d.z

$(filter-out %.c %.z, $(sources))

===>>return c.o 可以看出c.o被保留了下来


filter作用相反,返回不是以.c结尾的字符

Result




3.7 sort 排序函数


$(sort <list>)

功能:给list中的单词排序(升序),去掉重复的单词

Return 没有重复的、空格分隔的单词


object的内容进行排序,如果有重复的字符,则只显示一个

Result:




3.8 word 取单词函数


$(word number,text)

功能:取出text中第number个单词,number不能为0,会报错,超过最大值,返回空字符串

$(word 2,”abc”) return : b


返回object内容的第三个字符串

Result




3.9 wordlist 取字符串函数


$(wordlist start,end,text)

功能:从text中取出从startend的单词,start,end都是从1开始的

$(worlist 1,3,”abcd”) return:abc


Result




3.10 words 计算单词数量


$(words , text )

功能:统计text中字符数量


返回object中字符串的个数

Result:

5

返回个数。


3.11 firstword 取首单词的函数


$(firstsword ,text)

功能:取text中的第一个字符


返回object里第一个字符串

Result




文件处理函数


3.12 dir 取目录函数


$(dir names....)

功能:从names中取出各个文件目录。Return空格隔开的目录。如果没有目录就认为此文件为当前目录“./下的文件

$(dir src/foo.c hacks.c)===>>return : src/ ./


返回所有文件的路径,如果在本目录,则返回./

Result




3.13 notdir 取文件名函数


$(notdir names..)

功能:从names中取出各个文件名称。Return空格隔开的文件名

$(notdir src/foo.c hack.c)==>>return : foo.c hack.c


返回文件名,前面的路径全部抛弃

Result;




3.14 suffix 取后缀名函数


$(suffix names)

功能:从names中取出各个文件的后缀名

$(suffix src/foo.c hack.c)==>>return : .c .c


返回所有文件的后缀名

Result




3.15 basename 取前缀函数


$(basename names...)

功能:从names中取出各个文件的前缀名

$(basename src/foo.c hack.c)====>>return : src/foo hack


返回所有文件名的前缀,和suffix相反,抛弃掉文件后缀名

Result:




3.16 addsuffix 加后缀函数


$(addsuffix suffix,names..)

功能:给names中的各个文件添加后缀suffix

$(addsuffix .c,foo.c hack)====>>return : hack.c


给文件名加上后缀名

Result:




3.17 addprefix 加前缀函数


$(addprefix prefix,names...)

功能:给names中的各个文件添加前缀prefix

$(addprefix src/,foo.c hack)====>>return : src/foo.c src/hack


给文件名加上前缀,和addsuffix相反

Result




3.18 Join 单词连接函数


$(join name1,name2)

功能:使name1中的第一个单词和name2中的第一单词合并成一个新单词,后面依次类推,返回被空格分隔的序列

$(join src/foo hack,.c .c)===>>return : src/foo.c hack.c

注意:当name1name2数目不相同时,多余的部分将做为返回值的一部分。

所以这个函数可重建被dirnotdir分解的列表

        


object的第一个字符串和name的第一个字符串向Join,第二个和第二个相加,依次类推;当字符串个数不同时,直接显示剩下的字符串。

Result





    1. wildcard获得匹配模式函数


$(wildcard pattern…)

功能:列出当前目录下所有符合pattern模式的文件名。还可以判断文件是否存在

例如:sources:=$(wildcard *.c,*.h)

Isexits :=$(wildcard a.c) ##判读a,c是否存在,存在返回文件名,不存在返##回空字符

                  

              判断hello.c文件是否存在,存在返回文件名,否则返回空

Result



流程控制函数


3.20 if


$(ifcondition,then-part[,else-part])

功能:当conditiontrue,返回then-part;conditionfalse,返回else-part

当没有第三个参数时,conditionfalse,返回空


上图中,判断if后面的条件真假($(object));为真时,获得第一个值,为假时,获得第二个值。因为object没有赋值,所以条件为假。

Result:


    1. foreach


$(foreach var,list,text)

功能:类似shell中的for,执行时把list中使用空格分隔的单词依次取出复制给var,然后执行text表达式,重复直到list最后一位,为空时结束。

先展开varlist的变量,text中的变量直到被引用或执行时才会展开。因此text中对var的引用,var在每次被展开时会得到不同的值

Return :空格分隔的多次表达式text的计算结果


例:letters:=$(foreach letter,a b c d,$(letter))

Show-words

Litters has $(words $(letters))words : ‘$(litters)’


#### return : litters has 4words: ‘a b c d’


上图中,先将object的一个值赋值给变量var,然后在执行最后的$(var).l操作,所以第一个值被打印出来是a.c.l;后面的执行同样的操作。。

Result




    1. shell


$(shell command)

功能:需要一个shell命令作为他的参数,而返回的结果就是commandshell中的执行结果。Make仅对他的返回值的处理。输出中一系列的换行符号都会被换成单一的空格符号,接在后面的换行符号都会被删除,标准错误以及任何程序的结束状态都不会被返回。


可以直接执行shell后面的command;直接返回执行结果。

Result




3.23 origin

$(origin var)

功能:查询一个变量的出处,返回var的定义方式

类型:Undefined;default; environment; environment override; file; command line;

override; automatic .


返回变量的出处。比如说例子的file类型

Result




3.24 call 函数

$(call var,param,param….)

功能:call函数是唯一的一个可以创建定制参数化的引用函数。可以将一个变量定义为一个复杂的表达式,用call函数根据不同的参数来对他展开获得不同的结果。


可以理解为调用方法,后面的参数用逗号隔开,$(shelldate -u)是获得UTC时间。

Result


3.25 value 函数


$(value var)

功能:不对var进行任何展开操作,直接返回变量var代表的值,var是一个变量名,一般不包含$

返回:变量var所定义文本值


直接返回一个变量的值

Result



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值