Makefile语法

  1. Makefile规则格式
  2. 更新依赖
  3. make工具就是在makefile中一层一层的查找依赖和关系,并执行相应的命令,编译出最终的可执行文件
  4. Makefile变量
  5. 赋值符”=”
  6. 赋值符:”:=”
  7. 赋值符: “?=”
  8. Makefile模式规则
  9. MakeFile自动化变量
  10. $@ 规则中的目标集合,在模式规则中,如果有多个目标的话,”$@”表示匹配模式中定义的目标集合
  11. $% 当目标是库函数的时候表示规则中的目标成员名,如果目标中不是库函数文件,那么其值为空
  12. $< 依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么”$<”就是符合模式
  13. 的一系列的文件集合
  14. $^ 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,只保留一份
  15. $+ 和”$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件
  16. $* 这个变量表示目标模式中“%”及其之前的部分,如果目标是test/a.c,目标模式为a.%.c,那么“$”就是test/abbrlink
  17. Makefile伪目标
  18. 伪目标
  19. Makefile条件判断
  20. subst 字符串替换 $(subst ,,)
  21. pathsubst 用来完成模式字符串的字符串替换 $(patsubst ,,)
  22. dir 函数dir用来获取目录 $(dir <names…>)
  23. notdir 从文件名提取非指定目录 $(notdir <names…>)
  24. foreach $(foreach ,,) 循环
  25. willdcard (wildacrd pattern) 符合规则的字符串

Makefile规则格式

目标….. : 依赖文件集合…..

命令1

命令2

命令3

更新依赖

比如下面这条规则


main: main.o input.o calc.o  

  gcc -o main main.o output.o calc.o  

这条规则的目标是main,main.o,input.o和calcu.on是生成main的文件

  • 如果更新目标main,就必须先更新它的所有依赖文件

  • 如果依赖文件中的任何一个有更新,那么目标也必须更新

    “更新”就是执行一遍规则中的命令列表

用”tab”无空格

命令列表中的每条命令必须以Tab建开始, 不能使用空格

make命令会为MakeFile中的每个以TAB开始的命令创建一个shell进程去执行

MakeFile执行顺序

示例分析

  
main: main.o input.o calcu.o

  gcc -o main main.o input.o calcu.o  

main.o : main.c  

  gcc -c main.c  

input.o:input.c  

  gcc -c input.c   

calcu.o:calcu.c   

clean:  

  rm *.o  

  rm main  

上诉代码一共有5条规则

  • 1-2行为第一条规则

  • 3-4行为第二条规则

  • 5-6行为第三条规则

  • 7-8行为第四条规则

  • 10-12为第五条规则

    make命令在执行这个Makfefile的时候其执行步骤如下

  1. 首先更新第一条规则中的main,第一条规则的目标成为默认目标,只要默认目标更新了就认为Makefile的工作完成

  2. 在第一次编译的时候由于main还不存在,因此第一条规则会执行,第一条规则依赖于文件main.o,inout.o,和calu.o

  3. 这三个.o文件目前都还没有,因此必须先更新这三个文件,make会查找以这三个.o文件为目标的规则并执行。以main.o

    文件为例,发现更新main.o是第二条规则,因此会执行第二条规则,第二条规则里面的命令以”gcc -c main.c”,这行命令

    很熟悉了吧,就是不链接编译main.c,生成main.o,其他两个.o文件同理。

  4. 最后一个规则目标是clean,它没有依赖文件,因此会默认依赖文件都是最新的,所以其对应的命令不会执行,当我们

想要执行clean的话可以直接使用命令”make clean”,执行以后就会删除当前目录下所有.o文件以及main,因此clean的功能

就是完成工程的清理,”make clean”的执行过程如图所示(当执行”make clean”命令以后,前面编译出的的.o文件和main可

执行文件都被删除了,也就是完成了工程清理工作)

make工具就是在makefile中一层一层的查找依赖和关系,并执行相应的命令,编译出最终的可执行文件

Makefile的好处是”自动化编译”,一旦写好了makefile文件,以后只需要一个make命令既可完成整个工程的编译,极大的提高了

开发效率。

除了Makefile的”终极目标”所在的规则以外,其他规则的顺序在Makefile中是没有意义的。

“终极目标”就是指在是使用make命令的时候没有指定具体的目标时,make默认的那个目标,它是Makefile文件中的第一个规则的

目标,如果Makefile中的第一个规则有多个目标,那么这些目标中的第一个目标就是make的”终极目标”

Makefile变量

跟C语言一样MakeFile也支持变量的,先看一下前面的例子


main: main.o input.o calcu.o

  gcc -o main main.o input.o input.o calcu.on

上诉Makefile语句中,main.o input.o和calcu.o的三个依赖文件,我们输入了两遍,我们这个Makefile

比较小,如果Makefile复杂的时候这种重复输入的工作机会非常浪费时间,而且容易输错

为了解决这个问题,Makefile加入了变量的宏,不像C语言中的变量有int,char等各种类型,MakeFile中的变量

都是字符串!,类似C语言中的宏。使用变量将上面的代码修改,修后以后如下所示


#MakeFile 变量的使用

objects = main.o input.o calcu.o

main: ${objects}

gcc -o main ${objects}

我们来分析一下上诉Makefile

  • 第一行的事注释,Makkefile中可以写注释,注释开头要用符号”#,不能使用C语言中的”//“或者”/**/“

  • 第二行中我们定义了一个变量objects,并且给这个变量进行了赋值,其值为字符串“main.o input.o calcu.o ”

  • 第三行和第四行用到了变量objects,Makefile中变量的引用方法是”${变量名}”,比如本例中”${objects}”就是使用变量

在”示例代码”中我们在定义变量objects的时候使用“=”对其进行了赋值,Makefile变量的赋值符还有其他两个”:=”和”?=”

赋值符”=”

使用”=”在给变量赋值的时候,不一定要用已定义好的值,也可以使用后面定义的值,比如如下代码

赋值符:”:=”

因为赋值符”:=”不会使用后面定义的变量,只能使用前面已经定义好的,这就是”=”和”:=”的两个区别

赋值符: “?=”

如果前面的变量没有赋值,那么此变量就赋正在赋予的值

Makefile模式规则

模式规则中,至少在规则的目标中定义要包含”%”,否则就是一般规则,当”%”出现在目标的时候,目标中”%”

所代表的值决定了依赖中的”%”值

目标中的“%”表示对文件名的匹配,”%”表示长度任意的非空字符串,比如”%.c”就是所有以.c结尾的文件**,

类似于通配符**,类似于通配符**,a.%.c表示以a开头,以c结尾的所有文件

MakeFile自动化变量

目标和依赖中都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,

如何通过一行命令从不同的依赖文件中生成对应的目标?自动化变量就是完成这个动作的

所谓自动化变量就是这种变量会把模式中所定义的的一系列的文件自动的挨个取出,直至所有的符合模式的文本

都取出,自动化变量只出现在规则的命令中

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

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

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

的一系列的文件集合

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

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

常用的有三种


# $@,$<.$^

 objects = main.o input.o calcu.o

 main: ${objects}
  
  gcc -o main ${objects}

%.o : %.c

  gcc -c $<

clean 

  rm *.o

  rm main

Makefile伪目标

Makefile有一种特殊的目标-伪目标,一般的目标名都是要生成的文件,而伪目标不代表真正的目标名,

在执行make命令的时候通过指定这个伪目标来执行其所在规则的定义的命令

而且伪目标主要是避免Makefile的定义的执行命令和工作目录中的目标和工作目录下的实际文件出现名字的冲突

有时候我们需要编写一个规则来执行一些命令,但是这个规则不是用来创建文件的,比如在前面的“示例代码中”有如下

代码用来完成清理工程的功能:


clean 
 
 rm *.o

 rm main

伪目标

当和文件名和Makefile的内置变量有冲突时,使用伪变量,不影响Makefile的内置变量


.PHONY:clean

Makefile条件判断

在C语言中我们通过条件判断语句来根据不同的情况来执行不同的分支,MakeFile也执行条件判断,语法有两种:


  <条件关键字><条件为真时执行的语句> 

以及


<条件关键字><条件为真时执行的语句>

else

<条件为假时执行的语句>

endif

MakeFile条件控制语句,条件关键字有四个


ifeq (<参数名>,<参数2>)

ifeq '<参数1>','<参数2>'

MakeFile函数使用

MakeFile支持函数,类似C语言一样,MakeFile中的函数是已经定义好的,我们直接使用,不支持我们自定义的函数。

make所支持的函数不多,但是决对够我们使用了,函数的用法如下:


$(函数名 参数集合)

或者:

{函数名 参数集合}
  • 调用函数和调用普通变量一样,使用符号”$”来标识

  • 参数集合是函数的多个参数,参数之间以逗号”,”分隔

  • 函数名和参数之间以“空格”分隔开,函数调用以“$”开头

常用函数

subst 字符串替换 $(subst ,,)

此函数的功能是将字符串的中的内容替换成,函数返回被替换以后的字符串,比如如下示例

pathsubst 用来完成模式字符串的字符串替换 $(patsubst ,,)

函数patsubst用来完成模式字符串的替换,此函数查找字符串中的单词是否符合模式,如果匹配就用

来替换,可以使用通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串,如果

中也包含“%”,那么中的”%”将是所代表的字符串

dir 函数dir用来获取目录 $(dir <names…>)

此函数用来从文件序列中提取目录的部分,返回值是文件名序列的目录

notdir 从文件名提取非指定目录 $(notdir <names…>)

此函数用于从文件名序列中提取出文件名非目录的部分

foreach $(foreach ,,) 循环

此函数的作用就是把参数中的单词逐一取出来放到参数中中,然后再执行所包含的表达式

每次都会返回一个字符串,循环的过程中,中所包含的每个字符串会以空格隔开,最后当整个循环结束时

所返回的每个字符串组成的每个整个字符串都会是foreach函数的返回值

willdcard (wildacrd pattern) 符合规则的字符串


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 ggchzzz@163.com

文章标题:Makefile语法

字数:2.8k

本文作者:ggchzzz

发布时间:2022-08-14, 02:31:56

最后更新:2023-12-22, 23:17:54

原始链接:https://anska.info/post/1660415580823.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

github