Makefile
在Linux系统中,可以通过make指令完成Makefile文件的执行,make指令是一个命令工具,是一个解释Makefile文本的命令工具,也可以说它是一个工程管理器软件工具。
如果打算使用该指令,则需要在Linux系统中安装该指令:sudo apt install make,如下:

可以看到,用户在编写makefile文件的时候,该文件的名称应该是makefile或者Makefile,建议大家使用Makefile作为该脚本文件的名称,注意:该文件是没有拓展名的!!!
注意:make是一个shell命令,用于执行makefile文件中的命令(gcc xxx.c -o xxx),前提是执行make指令的时候,当前路径下需要有makefile文件,如果没有makefile文件,则指令make指令时会报错。
通过GNU组织提供的Make手册可以知道,Makefile文件的基本规则是有四部分组成,分别是目标、先决条件、制表符、命令,具体的规则如下所示:


注意:
(1)<tab符>即是制表符,即Tab键,不能用空格代替;也是因为这个制表符,make才知道后面是一个需要执行的shell命令。
(2)目标(需要有)以及其后的依赖列表(可以没有),以及其下的shell命令(可以没有),统称为一套规则。
(3)对于是编译代码的Makefile配置文件而言,如果依赖列表中有一个及以上的文件的时间戳比目标文件新,则执行编译源代码命令,否则不执行编译源代码命令。
一般编译过程:
image:a.o b.o x.o y.o
gcc a.o b.o x.o y.o -o image
a.o:a.c
gcc a.c -o a.o -c
b.o:b.c
gcc b.c -o b.o -c
x.o:x.c
gcc x.c -o x.o -c
y.o:y.c
gcc y.c -o y.o -c
可以看到不够简便
所以Makefile中有以下几种变量:
自定义变量
系统预定义变量
自动化变量
在Makefile中变量的特征有以下几点:
1)变量和函数的展开(除规则的命令行以外),是在make读取Makefile文件时进行的,这里的变量包括了使用“=”定义和使用指示符“define”定义的变量。
2)变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。
3)变量名不能包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在以后的make版本中被赋予特殊含义,并且这样命名的变量对于一些Shell来说不能作为环境变量使用。
4)变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式,这并不是要求的。但需要强调一点:对于一个工程,所有Makefile中的变量命名应保持一种风格,否则会显得你是一个蹩脚的开发者(就像代码的变量命名风格一样),随时有被鄙视的危险。
5)另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“<”、“@”、“?”、“*”、“@D”、“%F”、“^D”等等,后面会详述之。
6)变量的引用跟Shell脚本类似,使用美元符号和圆括号,比如有个变量叫A,那么对他的引用则是$(A),有个自动化变量叫@,则对他的引用是$(@),有个系统变量是CC则对其引用的格式是$(CC)。对于前面两个变量而言,他们都是单字符变量,因此对他们引用的括号可以省略,写成$A和$@。
(1)自定义变量,例如:
以上三个变量都是自定义变量,其中变量A包含了一个单词,变量B的值包含了三个单词,变量C的值引用了变量A的值,因此他的值是“apple tree”。如果要将这三个变量的值打印出来,可以这么写:既然是类似宏,所以在使用是需要添加特殊符号的: $( )
点击查看代码
gec@ubuntu:~$ cat Makefile -n
1 A = apple
2 B = I love China
3 C = $(A) tree
4
5 all:
6 @echo $(A) //echo前面的@代表命令本身不打印出来
7 @echo $(B)
8 @echo $(C)
gec@ubuntu:~$ make
apple
I love China
apple tree
点击查看代码
gec@ubuntu:~$ cat Makefile -n
1 OBJ = a.o b.o x.o y.o
2
3 image:$(OBJ)
4 gcc $(OBJ) -o image
5
6 a.o:a.c
7 gcc a.c -o a.o -c
8 b.o:b.c
9 gcc b.c -o b.o -c
10 x.o:x.c
11 gcc x.c -o x.o -c
12 y.o:y.c
13 gcc y.c -o y.o -c
14 clean:
15 rm $(OBJ)
(2)系统预定义变量
CFLAGS、CC、MAKE、Shell等等,这些变量已经有了系统预定义好的值,当然我们可以根据需要重新给他们赋值,例如CC的默认值是gcc,当我们需要使用gcc编译器的时候可以直接使用:
点击查看代码
gec@ubuntu:~$ cat Makefile -n
1 OBJ = a.o b.o x.o y.o
2
3 image:$(OBJ)
4 $(CC) $(OBJ) -o image
5
6 a.o:a.c
7 $(CC) a.c -o a.o -c
8 b.o:b.c
9 $(CC) b.c -o b.o -c
10 x.o:x.c
11 $(CC) x.c -o x.o -c
12 y.o:y.c
13 $(CC) y.c -o y.o -c
14 clean:
15 rm $(OBJ)
点击查看代码
gec@ubuntu:~$ cat Makefile -n
1 OBJ = a.o b.o x.o y.o
2 CC = arm-Linux-gcc #此处为自定义变量,覆盖系统预定义变量
3
4 image:$(OBJ)
5 $(CC) $(OBJ) -o image
6
7 a.o:a.c
8 $(CC) a.c -o a.o -c
9 b.o:b.c
10 $(CC) b.c -o b.o -c
11 x.o:x.c
12 $(CC) x.c -o x.o -c
13 y.o:y.c
14 $(CC) y.c -o y.o -c
15 clean:
16 rm $(OBJ)
注意:此时的CC就不再是gcc而是交叉工具链arm-Linux-gcc了。Makefile文件中注释使用#号。
常用的系统预定义变量,请看下表:
变量名 含义 备注
AR 函数库打包程序,可创建静态库.a文档。默认是“ar”。 无
AS 汇编程序。默认是“as”。 无
CC C编译程序。默认是“cc”。 无
CXX C++编译程序。默认是“g++”。 无
CPP C程序的预处理器。默认是“$(CC) –E”。 无
RM 删除命令。默认是“rm –f”。 无
ARFLAGS 执行AR命令的命令行参数。默认值是“rv”。 无
ASFLAGS 汇编器AS的命令行参数(明确指定“.s”或“.S”文件时)。 无
CFLAGS 执行CC编译器的命令行参数(编译.c源文件的选项)。 无
CXXFLAGS 执行g++编译器的命令行参数(编译.cc源文件的选项)。 无
(3)自动化变量
<、@、?、#等等,这些特殊的变量之所以称为自动化变量,是因为它们的值会“自动地”发生变化,可以类比普通变量,只要你不给它重新赋值,那么它的值是永久不变的,比如上面的系统预定义CC变量,只要不对它重新赋值,CC永远都等于gcc。
也就是说自动化变量的值是可以改变的,不是固定的。例如@,不能说 @ 的值等于某个固定值,但是它的含义的固定的:@ 代表了其所在规则的目标的完整名称。
有关自动化变量的详细情况,见下表:
@ 代表其所在规则的目标的完整名称
% 代表其所在规则的静态库文件的一个成员名
< 代表其所在规则的依赖列表的第一个文件的完整名称
? 代表所有时间戳比目标文件新的依赖文件列表,用空格隔开
^ 代表其所在规则的依赖列表 同一文件不可重复
- 代表其所在规则的依赖列表 同一文件可重复,主要用在程序链接时,库的交叉引用场合。
- 在模式规则和静态模式规则中,代表茎 茎是目标模式中“%”所代表的部分(当文件名中存在目录时,茎也包含目录(斜杠之前)部分。
上述列出的自动量变量中。其中有四个在规则中代表一个文件名(@、<、%和*)。而其它三个的在规则中代表一个文件名的列表。
使用自动化变量,可把之前的Makefile文件修改如下:
点击查看代码
gec@ubuntu:~$ cat Makefile -n
1 OBJ = a.o b.o x.o y.o
2
3 image:$(OBJ)
4 $(CC) $^ -o $(@)
5
6 a.o:a.c
7 $(CC) $^ -o $(@)-c
8 b.o:b.c
9 $(CC) $^ -o $(@) -c
10 x.o:x.c
11 $(CC) $^ -o $(@) -c
12 y.o:y.c
13 $(CC) $^ -o $(@) -c
14 clean:
15 rm $(OBJ)
静态规则
所谓的静态规则,其工作原理是:$(OBJ)被称为原始列表,即(a.o b.o x.o y.o),紧跟在其后的%.o被称为匹配模式,含义是在原始列表中按照这种指定的模式挑选出能匹配得上的单词(在本例中要找出原始列表里所有以.o为后缀的文件)作为规则的目标。如下所示:
点击查看代码
gec@ubuntu:~$ cat Makefile -n
1 OBJ = a.o b.o c.o
2
3 image:$(OBJ)
4 $(CC) $(OBJ) -o image
5
6 $(OBJ):%.o:%.c
7 $(CC) $(^) -o $(@) l -c -Wal
8
9 clean:
10 $(RM) $(OBJ) image
11
12 .PHONY: clean
静态规则工作原理整个过程用下图演示:

简单地讲,就是用一个规则来生成一系列的目标文件。接着,第二个冒号后面的内容就是目标对应的依赖,%可以理解为通配符,因此本例中%.o:%.c的意思就是:每一个匹配出来的目标所对应的依赖文件是同名的.c文件,这个过程也用图演示如下:


总结一下,静态规则是:当规则存在多个目标时,不同的目标可以根据目标文件的名字来自动构造出依赖文件(即只需写出目标名,即可寻找相应同名字的依赖文件)。
浙公网安备 33010602011771号