理解Makefile

本次笔记是看了陈皓的《跟我一起写Makefile》而作的整理,原版链接地址如下

http://pan.baidu.com/s/1skBumRF


第一部分

一、Makefile介绍

make命令编译和链接文件的的规则是:

1、如果这个工程没有编译过,那么我们所有的C文件都要编译并被链接。

2、如果这个工程的某几个C文件被修改,那么我们只需编译被修改的C文件,并链接目标文件。

3、如果这个工程的头文件被修改了,那我我们要编译引用这个头文件的几个C文件,并链接目标程序


二、Makefile的规则

Makefile规则如下:

target...:prerequisites...

command

target也就是目标文件,可以是.obj文件也可以是执行文件,还可以是一个标签(Label)

prerequisites就是要生成那个target所需要的文件或是目标,一般称为“依赖”

command也就是make需要执行的命令(需要注意的是,command命令一定要以tab键作为开头)

根据make的编译规则,如果prerequisites中有一个以上的文件比target文件要新的haul,command命令会被执行,这就是Makefile的核心内容。

make命令会根据文件的依赖性一层一层地寻找对应的文件,直到最终编译出第一个目标文件。在寻找的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make会直接退出,并报错。而对于所定义的命令的错误,或是编译不成功,make根本不去理会。


三、Makefile如何工作

在Makefile中可以使用变量,使其更容易维护,Makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。实现如下:

假如我们有 main.o  key.o  command.o  search.o insert.o  file.o init.o display.o这几个.obj文件,那么我们在Makefile一开始就这样定义:

obj=main.o  key.o  command.o  search.o insert.o  file.o init.o display.o  

在Makefile中就以“$(obj)”的方式来使用这个变量了,而假如我们需要添加新的obj文件,只需要在定义中添加即可,灰常方便


四、Makefile自动推导

GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没有必要去在每个.o文件后面写上依赖的命令,make能自动识别,因此在.o文件下只需要写所依赖的.h文件即可。一个例子如下:

原先的规则如下:

main.o: main.c  defs.h 

cc -c main.c 

 由于make的自动推导,可以简化写为

main.o:  defs.h 


五、清空文件的规则

每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于编译,也有利于保持文件的清洁。

比较良好的清理规则如下:

.PHONY:clean

clean:

-rm  edit  $(obj)

.PHONY的意思表示clean是一个伪目标,而在rm参数前加一个减号的意思是,也许某些文件出现问题,但不要管,继续做后面的事情。当然,clean规则不要放在开头,否则被当成第一个目标文件。其中一个潜规则是——将clean放在文件的最后。


第二部分

一、Makefile里面有什么?

Makefile主要包含这5个东西:显示规则、隐晦规则、变量定义、文件指示和注释

1、显示规则

显示规则说明了如何生成一个或者多个目标文件。这是有Makefile书写者明显指出,要生成的文件,文件的依赖文件,生成的命令

2、隐晦规则

由于我们的make有自动推导的功能,所以隐晦规则可以让我们较为粗糙简略地书写Makefile

3、变量的定义

在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个类似于C语言的宏。

4、文件指示

其包括三个部分,1)在一个Makefile中引用另一个Makefile,就像C语言中的include一样;2)指根据某些情况制定Makefile中的有效部分,就像C语言中的预编译#if一样;3)定义一个多行命令

5、注释

Makefile中只有行注释,用#字符执行

二、引用其他的makefile

在makefile中使用关键字include可以把别的makefile文件包含进来,语法和C语言的一样:include<filename>

filename可以是当前操作系统shell的文件模式,(可以包含路径和通配符),在include前面可以有一些空格字符,但是绝不能是tab键开始。

如果make命令找不到所包含的文件,不会第一时间出现致命的错误,此时会发出一条警告,接着继续寻找其他被包含的文件,过最后还是没有找到那个文件,make才会出现一条致命信息。

为了解决上述问题,可以在include前面加一个减号,表示无论include过程中出现什么错误,都不要报错,继续执行。

三、make工作方式

GNU的meke工作时执行的步骤如下:(其他的make也类似)

1、读入所有的makefile

2、读入被include的其他makefile

3、初始化文件中的变量

4、推到隐晦规则,并分析所有规则

5、为所有的目标文件创造依赖关系链

6、根据依赖关系,决定哪些目标需要重新生成

7、执行生成命令

1-5步骤为第一阶段,6-7步骤为第二阶段

第三部分 书写规则

一、规则语法

target...:prerequisites...

command

或是

target...:prerequisites...;command

若command和它们在同一行,那么应该以分号(英文输入格式)作为分隔,若不在同一行,则应该以tab键开头。

二、在规则中使用通配符

make支持三种通配符分别是  *  ?  [...]

通配符代替了一系列的文件,比如*.c表示所有后缀为c的文件 

而需要注意的一个特殊情况是前面说道的定义变量,如下:

obj=*.o  然而使用了通配符之后,obj的值就是*.o,并不会展开,为了解决这个问题,可以这样定义:obj:=$(wildcard *.o)

三、伪目标

在前面提到的clean这个命令是一个伪目标,因为我们并不生成clean这个文件,仅仅是一个标签。由于它不是一个文件,所以make命令无法生成它的依赖关系和决定它是否要执行,我们只有通过显示地指明这个“”目标“”才能让其生效。看下面的例子

.PHONY : clean

只要有这个声明,不管是否有clean这个文件,要运行clean这个目标,只有“”make clean“”这样的命令,于是可以写为:

.PHONY:clean

clean:

-rm  edit  $(obj)


第四部分 补充

一、编译命令

arm-linux-objcopy 把一种目标文件中的内容复制到另一种类型的目标文件中。

arm-linux-objdump 显示一个或者更多目标文件的信息。使用选项来控制其显示的信息,它所显示的信息通常只有编写编译工具的人才感兴趣。


例子:

arm-linux-objdump -D -m arm boot_elf > boot.dis

-m后面跟的是cpu的架构,例子中表示arm架构,

表示将反汇编语言写入boot.dis中而不在终端显示。


二、编译参数的解释

-O优化参数,后面可跟数字来表示优化的级别。-O0表示不优化,大部分平台最多使用-O3,建议使用到-O2,另外-Os表示对代码的大小进行优化,生成尽可能小的机器码

-E仅仅对代码进行预处理,不编译。实际上是将头文件包含和宏定义展开。

-c紧急汇编及编译代码,不进行链接。也就是将源代码编译成.o文件

-S仅仅汇编而不进行编译及链接。也就是将源代码编译成汇编指令。

-o  filename 指明输出文件名。一般配-E -c -S三个命令来使用。例如:gcc -c a.c -o a.o

-w关闭所有告警提示

-Wall打开大部分告警提示,而不是全部。

-W对某些告警显示更详细的信息

-D定义宏。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值