Makefile

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值