Makfile学习0——基础知识

学习Makfile需要掌握的基础知识

一、基础规则

目标(target)…:依赖(prerequiries)…
<tab>命令(command)     #以TAB开头

make命令的使用:
执行 make 命令时,它会去当前目录下查找名为“Makefile”的文件,并根据它的指示去执行操作,生成第一个目标。
我们可以使用“-f”选项指定文件,不再使用名为“Makefile”的文件,比如:make -f Makefile.build。
我们可以使用“-C”选项指定目录,切换到其他目录里去,比如:make -C a/ -f Makefile.build
我们可以指定目标,不再默认生成第一个目标。make -C a/ -f Makefile.build other_target

二、Makefile 变量
1、定义变量

Makfile的定义变量要用到赋值符,“=”、“:=”、“?=”。还有追加“+=”

make 中对变量的赋值有两种方式:延时变量、立即变量。区别在于它们的定义方式扩展方式不同前者在这个变量使用时才扩展开,即当真正使用时这个变量的值才确定;后者在定义时它的值就已经确定了使用`=’,`?=’定义或使用 define 指令定义的变量是延时变量使用`:=’定义的变量是立即变量。需要注意的一点是,`?=’仅仅在变量还没有定义的情况下有效,即`?=’被用来定义第一次出现的延时变量。对于附加操作符`+=’,右边变量如果在前面使用(:=)定义为立即变量则它也是立即变量,否则均为延时变量。

A = xxx // 延时变量  变量的真实值取决于它所引用的变量的最后一次有效值。
B ?= xxx // 延时变量,如果这是第一次定义,则赋值成功;如果曾定义过,此赋值无效
C := xxx // 立即变量  变量的真实值取决于:=赋予的值。
D += yyy // 如果 D 在前面是延时变量,那么现在它还是延时变量;如果 D 在前面是立即变量,那么现在它还是立即变量

2、变量的导出(export):
在编译程序时,我们会不断地使用“make -C dir”切换到其他目录,执行其他目录里的 Makefile。如果想让某个变量的值在所有目录中都可见,要把它 export 出来
比如“CC = $(CROSS_COMPILE)gcc”,这个 CC 变量表示编译器,在整个过程中都是一样的。定义它之后,要使用“export CC”把它导出来。

 

三、Makfile的模式规则
  
使用模式规则,至少要包含“%”,否则就是一般规则。目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件。
  当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值,使用方法如下

%.o : %.c
    命令

四、Makefile的自动化变量
作用:通过一行命令来从不同的依赖文件中生成对应的目标。
自动化变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完。
自动化变量只应该出现在规则的命令中。

自动化变量  描述
$@

规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模
式中定义的目标集合。

$%

当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件,
那么其值为空

$<

依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么
“$<”就是符合模式的一系列的文件集合。

$? 所有比目标新的依赖目标集合,以空格分开。
$^

所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,
“$^”会去除重复的依赖文件,只保留一份。

$+ 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。
$*

这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模
式为 a.%.c,那么“$*”就是 test/a.test。

五、Makfile中使用shell命令:
比如:TOPDIR := $(shell pwd)。这是个立即变量,TOPDIR 等于 shell 命令 pwd 的结果。

六、在 Makefile 中怎么放置第 1 个目标
执行 make 命令时如果不指定目标,那么它默认是去生成第 1 个目标。所以“第 1 个目标”,位置很重要。有时候不太方便把第 1 个目标完整地放在文件前面,这时可以在文件的前面直接放置目标,在后面再完善它的依赖与命令。比如:

1 First_target: // 这句话放在前面
2 .... // 其他代码,比如 include 其他文件得到后面的 xxx 变量
3 First_target : $(xxx) $(yyy) // 在文件的后面再来完善
4 command

七、假想目标(伪目标)

一般的目标名都是要生成的文件,而伪目标不代表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。
使用伪目标的主要是为了避免 Makefile 中定义的执行命令的目标工作目录下的实际文件出现名字冲突。

clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)

如果当前目录下恰好有名为“clean”的文件,规则因为没有依赖,所以目标被认为是最新的,那么执行“make clean”时它就不会执行那些删除命令。为了避免这个问题,我们可以将 clean 声明为伪目标,声明方式如下:

.PHONY : clean

八、Makfile的条件判断

两对关键字:ifeq、ifneq、ifdef 和 ifndef

ifeq用法:

ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”

上述用法中都是用来比较“参数 1”和“参数 2”是否相同,相等则为真。ifneq用法类似,不过,不相等为真。

ifdef用法:

ifdef <变量名>
如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。

九、Makefile函数

  •  函数调用的格式
$(function arguments)

这里`function’是函数名,`arguments’是该函数的参数。参数和函数名之间是用空格或 Tab 隔开,如果有多个参数,它们之间用逗号隔开。

常用函数

  1. 字符串替换和分析函数

    • $(subst from,to,text) 在文本`text’中使用`to’替换每一处`from’。

    $(subst ee,EE,feet on the street)        #结果为‘fEEt on the strEEt’。   
    • $(patsubst pattern,replacement,text) 寻找`text’中符合格式`pattern’的字,用`replacement’替换它们。`pattern’和`replacement’中可以使用通配符。

      $(patsubst %.c,%.o,x.c.c bar.c)  #结果为:`x.c.o bar.o’。
    • $(strip string) 去掉前导和结尾空格,并将中间的多个空格压缩为单个空格。

      $(strip a b c )  #结果为`a b c’。
    • $(findstring find,in) 在字符串`in’中搜寻`find’,如果找到,则返回值是`find’,否则返回值为空。

      $(findstring a,a b c) #返回'a'
      $(findstring a,b c)   #返回''
    • $(filter pattern...,text) 去除’text‘中不符合格式‘pattern...'的字,返回由空格隔开且匹配格`pattern...’的字

      $(filter %.c %.s,foo.c bar.c baz.s ugh.h) #返回'foo.c bar.c baz.s'
    • $(filter-out pattern...,text) 去除’text‘中符合格式‘pattern...'的字,返回由空格隔开且不匹配格`pattern...’的字

      $(filter %.c %.s,foo.c bar.c baz.s ugh.h) #返回'ugh.h'
    • $(sort list)将‘list’中的字按字母顺序排序,并去掉重复的字。输出由单个空格隔开的字的列表。

      $(sort foo bar lose) #‘bar foo lose’
  1. 文件名函数

    • $(dir names...)抽取‘names...’中每一个文件名的路径部分,文件名的路径部分包括从文件名的首字符到最后一个斜杠(含斜杠)之前的一切字符。

      $(dir src/foo.c hacks) #‘src/ ./’
    • $(notdir names...)抽取‘names...’中每一个文件名中除路径部分外一切字符(真正的文件名)。

      $(notdir src/foo.c hacks) #‘foo.c hacks’
    • $(suffix names...)抽取‘names...’中每一个文件名的后缀。

      $(suffix src/foo.c src-1.0/bar.c hacks)#‘.c .c’
    • $(basename names...) 抽取‘names...’中每一个文件名中除后缀外一切字符。

      $(basename src/foo.c src-1.0/bar hacks) #src/foo src-1.0/bar hacks’
    • $(addsuffix suffix,names...)参数‘names...’是一系列的文件名,文件名之间用空格隔开;suffix 是一个后缀名。将 suffix(后缀)的值附加在每一个独立文件名的后面,完成后将文件名串联起来,它们之间用单个空格隔开。

      $(addsuffix .c,foo bar) #‘foo.c bar.c’
    • $(addprefix prefix,names...)参数‘names’是一系列的文件名,文件名之间用空格隔开;prefix 是一个前缀名。将 preffix(前缀)的值附加在每一个独立文件名的前面,完成后将文件名串联起来,它们之间用单个空格隔开。

      $(addprefix src/,foo bar) #src/foo src/bar’
    • $(wildcard pattern)参数‘pattern’是一个文件名格式,包含有通配符(通配符和 shell 中的用法一样)。函数 wildcard 的结果是一列和格式匹配的且真实存在的文件的名称,文件名之间用一个空格隔开。

      #若当前目录下有文件 1.c、2.c、1.h、2.h
      c_src := $(wildcard *.c) #‘1.c 2.c’
  1. 其他函数

    • $(foreach var,list,text)对 list 中的每一个元素,取出来赋给 var,然后把 var 改为 text 所描述的形式。

      objs := a.o b.o
      dep_files := $(foreach f, $(objs), .$(f).d) # 最终 dep_files := .a.o.d .b.o.d
    • $(if condition,then-part[,else-part]) 首先把第一个参数‘condition’的前导空格、结尾空格去掉,然后扩展。如果扩展为非空字符串,则条件‘condition’为‘真’;如果扩展为空字符串,则条件‘condition’为‘假’。 如果条件‘condition’为‘真’,那么计算第二个参数‘then-part’的值,并将该值作为整个函数 if的值。如果条件‘condition’为‘假’,并且第三个参数存在,则计算第三个参数‘else-part’的值,并将该值作为整个函数 if 的值;如果第三个参数不存在,函数 if 将什么也不计算,返回空值。 注意:仅能计算‘then-part’和‘else-part’二者之一,不能同时计算。

    • $(origin variable)变量‘variable’是一个查询变量的名称,不是对该变量的引用。所以,不能采用‘$’和圆括号的格式书写该变量,当然,如果需要使用非常量的文件名,可以在文件名中使用变量引用。 函数 origin 的结果是一个字符串,该字符串变量是这样定义的:

      ‘undefined' :如果变量‘variable’从没有定义;
      ‘default' :变量‘variable’是缺省定义;
      ‘environment' :变量‘variable’作为环境变量定义,选项‘-e’没有打开;
      ‘environment override' :变量‘variable’作为环境变量定义,选项‘-e’已打开;
      ‘file' :变量‘variable’在 Makefile 中定义;
      ‘command line' :变量‘variable’在命令行中定义;
      ‘override' :变量‘variable’在 Makefile 中用 override 指令定义;
      ‘automatic' :变量‘variable’是自动变量
    • $(shell command arguments) 函数 shell 是 make 与外部环境的通讯工具。函数 shell 的执行结果和在控制台上执行‘commandarguments’的结果相似。不过如果‘command arguments’的结果含有换行符(和回车符),则在函数 shell的返回结果中将把它们处理为单个空格,若返回结果最后是换行符(和回车符)则被去掉。

      #当前目录下有文件 1.c、2.c、1.h、2.h,则:
      c_src := $(shell ls *.c) #‘1.c 2.c’
posted @ 2020-05-10 00:29  不明白就去明白  阅读(314)  评论(0编辑  收藏  举报