Makefile
Makefilemakefile:进行编译+链接编译:将高级语言书写的代码转换为机器可以识别的机器指令。链接:将多个.o文件或者是.o文件与库文件链接成为可以被操作系统执行的可执行文件。 链接采用ld工具静态库:又称之为文档文件。是多个.o文件的集合, 使用ar工具维护和管理共享库:同样是多个.o文件的集合。但是这些.o文件是由编译器按照一种特殊的方式生成。linux下共享库的...
Makefile
makefile:进行编译+链接
编译:将高级语言书写的代码转换为机器可以识别的机器指令。
链接:将多个.o文件或者是.o文件与库文件链接成为可以被操作系统执行的可执行文件。 链接采用ld工具
静态库:又称之为文档文件。是多个.o文件的集合, 使用ar工具维护和管理
共享库:同样是多个.o文件的集合。但是这些.o文件是由编译器按照一种特殊的方式生成。linux下共享库的格式通常为elf格式。共享库已经具备了可执行的条件。
一般来说,不同厂商的make各不相同,也有不相同的语法,但是其本质都是在“文件的依赖性上做文章”。
1.makefile简介
1.1make规则
target : prerequisites
command
target: 可以是个object file。也可以是一个执行文件,还可以是一个标签(lable)
prerequisites :生成该target 的依赖文件
makefile的主线与核心内容:依赖文件中有任何一个文件比target要新的话,command就要执行(库文件除外)
make的工作过程:make会根据依赖关系一层层的去找文件,如果找不到文件会直接退出,并报错。但是对于命令所定义的错误,或者是编译失败,make并不会有提示。。make只负责文件的依赖性。
1.2makefile变量
objects =main.o
make自动推导功能:make看到文件,会自动的将.c文件加入依赖关系,
main.o:main.o def.h
cc -c main.c
转化为:
main.o : def.h
1.3清空目标文件
makefile中都应该有一个清空目标文件的命令,clean。一般放置于makefile文件的末尾。
ex:
.PHONY : clean
clean:
-rm edit $(objects)
1.4makefile中主要包含5个东西:显示规则、隐晦规则、变量定义、文件指示和注释。
1.5引用其他的makefile
include<filename>
被包含的文件会原模原样的放在当前文件的包含位置。filename可以是当前操作系统shell的文件模式。(可以包含路径和通配符)。
如果include没有指定绝对路径或者相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么make会在下面的几个目录下寻找:
1.如果make 执行时,有-I 或者 --include-dir参数,那么make就会在这个参数所指定的目录下去寻找 。
2.如果目录<prefix>/include存在的话。(一般是/usr/local/bin或者/usr/include)。make也会去该目录下寻找。
如果文件没有找到的话,make会产生一条警告信息,但是并不会直接退出,会继续载入其他的文件,一旦完成makefile的读取,make 会再重试这些没有找到的文件,如果还是找不到,那么会产生一条致命信息、
如果需要使make不理会无法读取的文件,可以在include前面加上-
-include <filename>
:表示,无论include出现什么错误,都不要报错,继续执行,和其他版本make兼容的指令是sinclude
1.6规则通配符
在make中支持三种通配符: * ? ~
使用方式和unix机器中相同
通配符可以使用在command当中,也可以使用在依赖当中,或者变量定义当中。
变量定义:objects=*.o 但是要注意的是:通配符并不会在变量中展开,变量定义就是*.o
如果需要通配符在变量中展开,需要使用 objects:=$(wildcard *.o)
1.7文件搜寻
Makefile文件中的VPATH变量,指定找寻目录。
如果没有指定这个变量,那么make只会在当前目录下寻找依赖文件和目标文件。但是如果定义了这个变量,make就会在当前目录找不到的情况下去寻找vpath指定目录下寻找。
VPATH=src:../headers 目录间由冒号分开,而且当前目录永远是最优先搜索的地方。
还可以使用make中的关键字vpath来指定路径,它不是变量,是make关键字。使用方法有三种:
vpath<pattern><directories> 在目录<directories>下搜索符合模式<pattern>的文件
vpath<pattern> 清除符合模式,<pattern>的文件搜索目录
vpath 清除所有已经被设置好的文件搜索目录
vpath %.h ../headers 在../headers目录下寻找所有以 .h结尾的文件
1.8伪目标
clean并不是一个目标文件,我们并不生成该文件,伪目标不是一个文件,而是一个标签。伪目标的取名并不能和文件名重名。
为了避免和文件名重名的情况,可以使用一个特殊的标记.PHONY来显式的致命一个目标是伪目标。可以向make 声明,不管是不是有这个文件,这个目标就是伪目标。
1.9使用伪目标来清除不同种类的文件
因为目标也可以成为依赖的特性,伪目标同样也可以成为依赖。
.PHONY: cleanall cleanobj cleandiff
cleanall: clean obj cleandiff
rm program
cleanobj:
rm *.o
cleandiff:
rm *.diff
2.0多目标的概念
在makefile中可能具有多个目标,如果多个目标依赖于同一个文件,而且其生成的命令类似,那么我们就可以将其合并起来。
2.1静态模式
静态模式可以更加方便的定义多目标
语法结构:
<targes ...>: <target-pattern> : <prereq-patterns...>
<commands>
...
targets:定义了一系列的目标文件,可以有通配符,是目标的一个集合。
target-pattern是指明了targets的模式,也就是目标集模式。表明targets中的文件名格式,比如都是.o文件, %.o
prereq-patterns: 目标的依赖模式。对target-pattern形成的模式再进行一次依赖目标的定义。
多目标与多依赖的概念要搞清楚。多依赖可以直接使用objects来定义。多目标的话需要使用静态模式来定义。伪目标相结合的方式,输出多个目标文件。
2.2自动生成依赖性
在C/C++编程的时候,我们需要添加或者删除头文件,不可能去makefile里面去修改其依赖关系,可以使用-M选项
cc -M main.c 输出: main.o:main.c def.h
如果使用gcc的话,需要使用-MM参数,否则会包含一些标准库中的文件
为了将编译器的功能与我们的makefile联系在一起,GNU建议把编译器为每一个源文件自动生成的依赖关系放到一个文件中,为每一个name.c文件都生成一个name.d的Mkakefile,.d文件中就存放对应.c的文件依赖关系。
于是,我们可以写出 .c 文件和 .d 文件的依赖关系,并让 make 自动更新或生成 .d 文件,并把 其包含在我们的主 Makefile 中,这样,我们就可以自动化地生成每个文件的依赖关系了。
这个规则的意思是,所有的 .d 文件依赖于 .c 文件,rm -f $@ 的意思是删除所有的目标,也就是 .d 文件,第二行的意思是,为每个依赖文件 $< ,也就是 .c 文件生成依赖文件,$@ 表示模式 %.d 文 件,如果有一个 C 文件是 name.c,那么 % 就是 name ,$$$$ 意为一个随机编号,第二行生成的文件 有可能是“name.d.12345”,第三行使用 sed 命令做了一个替换,关于 sed 命令的用法请参看相关的 使用文档。第四行就是删除临时文件。
总而言之,这个模式要做的事就是在编译器生成的依赖关系中加入 .d 文件的依赖,即把依赖关系:
于是,我们的 .d 文件也会自动更新了,并会自动生成了,当然,你还可以在这个 .d 文件中加入的不 只是依赖关系,包括生成的命令也可一并加入,让每个 .d 文件都包含一个完赖的规则。一旦我们完成这 个工作,接下来,我们就要把这些自动生成的规则放进我们的主 Makefile 中。我们可以使用 Makefile 的“include”命令,来引入别的 Makefile 文件(前面讲过),例如:
上述语句中的 $(sources:.c=.d) 中的 .c=.d 的意思是做一个替换,把变量 $(sources) 所有 . c 的字串都替换成 .d ,关于这个“替换”的内容,在后面我会有更为详细的讲述。当然,你得注意次 序,因为 include 是按次序来载入文件,最先载入的 .d 文件中的目标会成为默认目标。
3.0显示命令
通常,make会将要进行的命令行执行前输出到屏幕上。但是我们使用@字符在命令行前,那么这个命令将不会被make显示出来。
make 参数: -n --just-print :仅仅在控制台上显示命令,用于调试命令
-s --silent --quiet全面禁止命令的显示
3.1命令执行
在执行shell命令时,比如文件更新以后要执行其依赖之后的命令
命令如果具有依赖性的话,比如两行命令,下一条命令依赖于上一条命令,那么这两条命令需要写在同一行当中,并且使用分号分隔。
3.2嵌套执行make
在大型工程当中,不同的源文件根据不同的功能放在不同的文件夹里面,我们可以在特定的目录中写一个该目录下的makefile,这样会使得makefile变得更加有条理,更容易组织整个系统的架构。
如果要在makefile中传递变量到下级makefile中,可以声明:
export <variable>; 取消声明: unexport <variable>
ex:
export variable=value 等价于 variable=value export variable 等价于 export variable:=value
如果需要传递所有的变量,那么只需要一个export即可,后面什么都不需要加。
但是需要注意的是,有两个变量SHELL+MAKEFLAGS,这两个变量总是要传递到下一层的。特别是 MAKEFLAGS 变量,其中包含了 make 的参数信息,如果我 们执行“总控 Makefile”时有 make 参数或是在上层 Makefile 中定义了这个变量,那么 MAKEFLAGS 变量将会是这些参数,并会传递到下层 Makefile 中,这是一个系统级的环境变量。所以不要轻易的定义环境变量,除非确信大家都会用到该选项。
在嵌套执行中较为有用的参数:
-w 或者 --print-directory会在make的过程中输出一些信息,可以看到当前的工作目录。
3.3定义命令包
如果在makefile中出现一些相同的命令序列,可以为这些命令序列定义一个变量,之后引用该变量即可。
这种命令序列的定义以define开始以endif结束。
更多推荐
所有评论(0)