makefile相当于一种脚本编程语言,可以使用变量、控制结构语句、函数,也可执行shell命令。
makefile是用来实现自动化编译,makefile区别于其他编程语言的最大特点就是,它的执行是由所编译文件的依赖关系驱动的。
1.makefile文件的组成
主要有五种部分:
(1)显式规则:什么是规则?
(2)隐式规则:由于make具有自动推导功能,所以隐晦的规则可以让人比较粗略的写makefile
(3)变量的定义:在makefile里,变量实际上就是字符串,makefile也可认为是做的是字符串处理工作。
(4)文件指示:1.引用另一个makefile文件,像include
2.根据某些情况指定Makefile中的有效部分,就像C中的预处理#if
3.定义一个多行的命令
(5)注释:用#注释,转义字符是\,如要输出#,可以\#。
2.makefile规则
make工具通过规则,确定所要编译文件之间的依赖关系,并进行编译。
(1)基本规则:
规则的两种形式:
第一 targets : prerequistites
command
....
第二 targets : prerequitites ; command
command
....
targets是目标,有两类目标,一是在执行过程中产生的文件名,如.o文件;二是某个动作,在执行过程中没有实际的文件与之对应。这种情况称为PHONY目标,只执行命令不产生文件。
command是命令,一般以tab键开头。如果和文件依赖规则在同一行,可以用“;”隔开
prerequisites表示生成目标文件所依赖的文件。如果其中某个文件比目标文件新,make工具会认为目标文件需要更新,make工具会生成新的目标文件。如果依赖过长,可以用“\”隔开
make工具对更新的定义:
第一 目标文件没有生成
第二 某个条件中的文件修改时间比目标文件晚
第三 某个条件中的文件需要更新
示例1:
- app : main.o lib.o drv.o
- gcc -o app main.o \ # \用作换行
- lib.o drv.o
- main.o : main.c head.h
- gcc -c main.c
- lib.o : lib.c lib.h
- gcc -c lib.c
- drv.o : drv.c drv.h
- gcc -c drv.c
- clean:
- rm *.o app
(2)隐式规则的使用 由于make具有自动推导功能,所以隐晦的规则可以让人比较粗略的写makefile。比如,make工具会自动的使用gcc -c 命令,将一个后缀为.c的源文件编译得到一个同名的.o目标文件。使用这个隐式规则,我们可以将上面的示例1改写为如下形式:
示例2
- app : main.o lib.o drv.o
- gcc -o app main.o \ # \用作换行
- lib.o drv.o
- main.o : head.h #得到main.o文件
-
- lib.o : lib.h #lib.o
-
- drv.o : drv.h
-
- clean:
- rm *.o app
(3)伪目标(目标,就是规则中的targets,有两种目标,前面已说明)
什么是伪目标?就是该目标不对应一个真正的目标文件,就像C语言中的标号,只执行命令,而不生成文件。make工具无法为不是具体文件的目标生成依赖关系,而且不能决定是否执行该目标。因此,需要人为的指明该目标,这里就是指明为clean,这叫做显式的指明。
为了避免与已存在的文件重名,有个方法,使用.PHONY 来显式的指明一个目标是伪目标,PHONY在英语里是虚假的,假冒的意思。
注意,是显式的。上面说的,当然就是隐式的。。
如:
.PHONY : clean
使用了PHONY这个关键字,表示不管是否有clean文件存在,都要将clean声明为伪目标。
示例3:第一个目标是默认目标(默认目标,如make后什么也不加,默认目标为文件中第一个目标,将其声明为伪目标,则默认目标每次都会被执行。)
- all : main.o lib.o drv.o
- gcc -o app main.o \ # \用作换行
- lib.o drv.o
- .PHONY all
- main.o : main.c head.h
- gcc -c main.c
- lib.o : lib.c lib.h
- gcc -c lib.c
- drv.o : drv.c drv.h
- gcc -c drv.c
- clean:
- rm *.o app
makefile中的第一个目标会被认作默认目标。这里,把all声明为伪目标。由于伪目标依赖的文件总是不如伪目标新,所以伪目标all所依赖的命令总是执行。
(4)规则中的通配符
make工具支持三种:*, ? , []
3.规则中使用的命令
(1)回显命令:echo
make工具可以使用@字符,将make执行过程中需要打印的信息不在屏幕输出。
如:@echo "initializing..."
(2)使用shell环境下的命令,如,cd,ls,pwd。
在两条命令之间加上 “;”,可以将上一条命令的结果应用在下一条上。
4.变量的使用
makefile中 的变量分为两种:立即变量+延时变量
=及?= 还有define用来定义延时变量, 其中?=只用在变量第一次被定义时
:= 用来定义立即变量
对于 += 来说,右边的变量是延时变量,那么它就是延时变量。 右边是立即变量,它就是立即变量。
在Makefile中,变量就是一个名字(像是C语言中的宏),代表一个文本字符串(变量的值)。在Makefile的目标、依赖、命令中引用一个变量的地方,变量会被它的值所取代(与C语言中宏引用的方式相同,因此其他版本的make也把变量称之为“宏”)。在Makefile中变量的特征有以下几点:
(1). Makefile中变量和函数的展开(除规则的命令行以外),是在make读取makefile文件时进行的,这里的变量包括了使用“=”定义和使用指示符“define”定义的。
(2). 变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。
(3). 变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在以后的make版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说不能作为环境变量使用。
(4). 变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式,这并不是要求的。但需要强调一点:对于一个工程,所有Makefile中的变量命名应保持一种风格,否则会显得你是一个蹩脚的程序员(就像代码的变量命名风格一样)。
(5). 另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“$<”、“$@”、“$?”、“$*”等。
$@:规则中的目标文件
$<:依赖列表中的第一个依赖
$^:依赖列表中的所有依赖
$*:目标模式中“%”及其之前的部分
$?:所有比目标新的依赖的集合,以空格隔开
阅读(2095) | 评论(0) | 转发(3) |