makefile语法详解

本文详细介绍了Makefile的核心规则,包括目标、依赖和命令的定义,以及make工具的工作原理。讲解了如何通过依赖关系决定目标文件的生成,以及make的执行步骤。同时,讨论了makefile中的变量、条件判断和函数的使用,以及如何通过vpath指定文件搜索路径。还涵盖了伪目标的概念,用于执行如清理等非文件生成任务。最后,提到了makefile的注释、文件引用和常用变量的总结。
摘要由CSDN通过智能技术生成

1.makefile核心与make工具概述

make 命令执行时,需要一个 Makefile 文件,以告诉 make 命令需要怎么样的去编译和
链接程序。makefile是一个路标,指引make这个工具怎么执行。
makefile这个路标的核心规则其实一条:

target:prerequisite
	command

–target 是一个目标文件,可以是Object文件,也可以是可执行文件
– prerequisites是要生成target所依赖的文件或目标
–command是make需要执行的生成target的命令
这是一个文件的依赖关系,也就是说,要生成的target 这一个或多个的目标文件依赖于
prerequisites 中的文件,其生成规则定义在 command 中。

而关于make,只需了解以下几点:
1.它是一个工具
2.执行make,工具会在当前目录下找makefile或Makefile文件
3.如果找到,它会找文件中的第一个目标文件(target),并把这个文件作为最终的目标文件。
4, 如果 target文件不存在, 或是 target所依赖的后面的 .o 文件的文件修改时间要比 target
这个文件新,那么,他就会执行后面所定义的命令来生成 edit 这个文件。

make的执行步骤如下:
1、读入所有的 Makefile。
2、读入被 include 的其它 Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

依赖性是make 与makefile的核心,make找生成目标文件的依赖关系,并执行命令,生成目标文件
而makefile要学的书写规则,书写命令,变量/语句/函数的使用等内容,说白了都是为上面的依赖性服务。

此外,make 的“隐晦规则”:
不需要这么写

main.o : main.c defs.h
cc -c main.c

make会自己推导main.o的目标文件有main.c,且命令里有cc -c main.c,所以只需按如下写法:

main.o : defs.h

2.makefile语法学习

makefile语法学习里主要包括五部分:显示规则,隐式规则,变量定义,文件指示,其它

2.1规则

这里的规则就是之前说的核心规则:
target:prerequisite
command
也就是依赖规则与目标生成方法。

格式如上,这里有几点说明:

  • command 是命令行,如果其不与“target:prerequisites”在一行,那么,必须以[Tab键]开头, 如果和 prerequisites 在一行, 那么可以用分号做为分隔。

  • 命令太长可以用\隔开,一行没有字符数限制。make 会以 UNIX 的标准 Shell,也就是/bin/sh 来执行命令。

  • target 或者prerequisite可以包含多个文件,以空格隔开。

  • target和prerequisite可以使用通配符: * :如“*.c”表示所以后缀为 c 的文件。

注意依赖文件prerequisite的搜索路径,可以通过VPATH指定。
VPATH是make的一个特殊变量,不是关键字,可以这样使用:
VPATH = src:…/headers
不同路径目录用冒号:隔开

也可以用小写vpath指定,注意,vpath是make的一个关键字,但是它更为灵活,用法如下:
1、vpath
为符合模式的文件指定搜索目录。
2、vpath
清除符合模式的文件的搜索目录。
3、vpath
清除所有已被设置好了的文件搜索目录。

pattern指定了文件集,directories指定了路径。pattern需要包含“%”字符。“%”的意思是匹配零或若干字符,如“%.h”表示所有以“.h”结尾的文件。例如:

vpath %.c foo:bar

make的最终目标是生成第一个makefile文件的第一个target文件,那么对于clean种命令就无法执行,所以,makefile引入了伪目标的概念。
伪目标就是假的”目标文件“,用.PHONY表示,如

.PHONY: clean
clean:
rm *.o temp

就是把clean当作一个”目标文件“,执行make clean来”生成这一目标“,进而达到了执行清除目标文件的目的。
伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的 Makefile 需要一口气生成若干个可执行文件,但你只想简单地敲一个 make 完事,并且,所有的目标文件都写在一个 Makefile 中,那么你可以使用“伪目标”这个特性:

all : prog1 prog2 prog3
.PHONY : all

前面说过,多依赖文件,可以通过*表示,多依赖的路径可以在vpath中用%指定,而多目标文件,可以用$@表示用在命令中,如

bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@

它相当于
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput

即$@相当于bigoutput littleoutput的集合。

规则的另一种写法

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

$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@

目标从$object 中获取,“%.o”表明要所有以“.o”结尾的目标,将这些目标后缀”.o“去掉,而依赖模式“%.c”,表示为刚才去掉”.o”的名称后加“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。
这种写法成为静态模式

2.2书写命令(command)

2.2.1命令显示

make中所有的命令都会在执行前被打印在命令行中
前面加@ 命令不会被make显示
而参数“-n”或“–just-print”则只打印不执行
参数“-s"或者”-slient"则这是全局不打印

2.2.2命令执行

命令执行时,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。

2.2.2命令出错

命令出错时会终止,忽略命令的出错,我们可以在 Makefile 的命令行前加一个减号“-”(在 Tab 键之后),标记为不管命令出不出错都认为是成功的。

2.3 书写变量

makefile中的变量定义,类似与c中的宏定义。变量会在使用它的地方精确地展开。
变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“ ”符号,但最好用小括号“()”或是大括号“ ”把变量给包括起来。如果你要使用真实的“ ”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来。如果你要使用真实的“ 符号,但最好用小括号()或是大括号把变量给包括起来。如果你要使用真实的”字符,那么你需要用“$$”来表示。
变量可以使用在许多地方,如规则中的“目标”、“依赖”、“命令”以及新的变量中。

变量赋值
使用=赋值:变量是可以使用后面的变量来定义的。
使用:=赋值:前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。
使用?=赋值:若没有定义则定义,否则什么也不做。
使用+=赋值:追加变量。如果变量之前没有定义过,那么, “+=”会自动变成“=”, 如果前面有变量定义, 那么“+=”会继承于前次操作的赋值符。如果前一次的是“:=”, 那么“+=”会以“:=”作为其赋值符

变量的高级用法
替换变量中的共有的部分,其格式是“ ( v a r : a = b ) ”或是“ (var:a=b)”或是“ (var:a=b)或是{var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符。
或 bar := $(foo:%.o=%.c)

makefile中“局部变量与全局变量”
当 make 嵌套调用时(参见前面的“嵌套调用”章节),上层 Makefile 中定义的变量会以系统环境变量的方式传递到下层的Makefile 中。在下层mk中重新赋值会覆盖变量。除非使用-e参数。
可以为某个目标文件设置局部变量,它可以和“全局变量”同名,因为它的作用范围只在这条规则以及连带规则中,所以其值也只在作用范围内有效。如:

prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o

在这个示例中,不管全局的$(CFLAGS)的值是什么,在 prog 目标,以及其所引发的所有规则中(prog.o foo.o bar.o 的规则),$(CFLAGS)的值都是“-g”。
或这样
%.o : CFLAGS = -O
给所有.o结尾的目标文件的CFLAGS 值赋值-O.

2.3使用条件判断

命令格式:

<conditional-directive>
<text-if-true>
else
<text-if-false>
endif

else部分非必须。条件关键字有四个:ifeq/ifneq、ifdef/ifndef

2.4 使用函数

函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$(<function> <arguments1>,<arguments2>…)

make支持的函数不多,大体如下:
在这里插入图片描述

2.5 其他规则说明

1.注释:
makefile中注释使用符号# ,若要使用#字符,可以用#转义
2.makefile的文件名
使用makefile或者Makefile或者xxx.mk,建议使用Makefile,因为第一个字母大写,更加显眼醒目
3.mk的文件引用
与C类似,mk中的文件引用使用的也是include关键字,比如:
include a.mk
与c一样,如果没有指定路径,mk寻找的路径默认为当前目录,如果当前目录没有找到,那么mk还会从以下目录寻找:

  • makefile中有”-I“或”–include-dir“参数指定的路径
  • 如果目录/include(一般是:/usr/local/bin 或/usr/include)存在的话,make 也会去找。

如果有文件没有找到的话,make 会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成 makefile 的读取,make 会再重试这些没有找到,或是不能读取的文件,如果还是不行,make 才会出现一条致命信息。

3 关键字总结

名称含义说明
vpath指定依赖文件的搜索路径

4 特殊变量总结

名称含义说明
VPATH依赖文件的包含路径用:分隔不同文件
$@当前规则中所有目标的集合

常用变量

语法定义的默认变量

变量说明
$@规则的目标所对应的文件名
$<规则中的第一个相关文件名
$^规则中所有相关文件的列表,以空格分割
$?规则中日期新于目标的所有相关文件的列表,以空格分割
$(@D)目标文件的目录部分
$(@F)目标文件的文件名部分

预定俗成需预定义的变量
在这里插入图片描述

待进一步完善…

makefile 实例分析 Makefile 语法分析 第一部分 VERSION = 2# 给变量VERSION赋值 PATCHLEVEL = 6# 给变量PATCHLEVEL赋值 SUBLEVEL = 22# 给变量SUBLEVEL赋值 EXTRAVERSION = .6# 给变量EXTRAVERSION赋值 NAME = Holy Dancing Manatees, Batman!# 给变量NAME赋值 # *DOCUMENTATION*# To see a list of typical targets execute "make help"# More info can be located in ./README# Comments in this file are targeted only to the developer, do not# expect to learn how to build the kernel reading this file. # Do not:# o use make's built-in rules and variables#    (this increases performance and avoid hard-to-debug behavour);# o print "Entering directory ...";MAKEFLAGS += -rR --no-print-directory# 操作符“+=”的作用是给变量(“+=”前面的MAKEFLAGS)追加值。# 如果变量(“+=”前面的MAKEFLAGS)之前没有定义过,那么,“+=”会自动变成“=”;# 如果前面有变量(“+=”前面的MAKEFLAGS)定义,那么“+=”会继承于前次操作的赋值符;# 如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符# 在执行make时的命令行选项参数被通过变量 “MAKEFLAGS”传递给子目录下的make程序。# 对于这个变量除非使用指示符“unexport”对它们进行声明,它们在整个make的执行过程中始终被自动的传递给所有的子make。# 还有个特殊变量SHELL与MAKEFLAGS一样,默认情况(没有用“unexport”声明)下在整个make的执行过程中被自动的传递给所有的子make。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值