什么是Makefile

makefile 关系到整个工程的编译规则,它定义了一系列规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译。

makefile带来的好处就是“自动化编译”,一旦编好,只需要一个make命令就可以完成整个工程的编译,极大的提高了编译效率。

make是一个命令工具,是一个解释makefile中指令的命令工具。

无论是C还是C++都需要将文件编译成中间代码文件,在windows下是.obj文件,在UNIX下是.o文件,这个动作叫做编译(complie)。然后把大量的Object File文件合成为可执行文件,这个过程叫做链接。

在编译时,需要的是编译文件的语法正确。

在链接时,需要告诉编译器头文件所在的位置。

一般来来说,每个文件都应该对一个.o/.obj文件。

链接时,主要是链接函数和全局变量。

在大多时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显的指出中间目标文件名,这对于编译很不方便,所以我们要给中间目标文件打个包,在windows下这种包叫“库文件”,也就是.lib文件,在UNIX下,就是.a文件。

MakeFile规则

target ... : prerequisites
command
...
...

target 是目标文件,可以是Object File文件,也可以是执行文件,也可以是一个标签。

prerequisites 是要生成的target所需要的文件或者目标

command 就是make需要执行的命令。

这是一个文件依赖关系,也就是说,target 这一个或者多个目标文件依赖于prerequisites中的文件,其生成规则定义在command中。

edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o 
    cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o

main.o : main.c defs.h
    cc -c main.c
kbd.o  : kbd.c defs.h command.h
    cc -c kbd.c
command.o :command.c defs.h command.h
    cc -c command.c
display.o : display.c defs.h buffer.h
    cc -c display.c
instert.o : insert.c defs.h buffer.h
    cc -c insert.c
search.o : search.c defs.h buffer.h
    cc -c search.c
files.o: files.c defs.h buffer.h command.h
    cc -c files.c
utils.o : utils.c defs.h
    cc -c utils.c

clean:
    rm edit mian.o kbd,o command.o display.o insert.o search.o files.o utils.o

我们可以将这个文件保存为Makefile/makefile,然后在该目录下直接输入命令“make”就可以生成执行文件edit。如果要删除执行文件和所有的中间文件,那么只要简单的执行一下“make clean”就可以了。

在这个makefile 中,目标文件target 包含: 

执行文件edit和中间目标文件(*.o)

依赖文件就是:后面的哪些.c和.h,每一个.o都有一组依赖文件,而这些.o又是执行文件 edit的依赖文件。依赖关系实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。

在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。make并不管命令是怎么工作的,他只管指令所定义的命令。make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。

clean 不是一个文件,他只不过是一个动作的名字,有点像C语言中的lable一样,其:后面什么也没有,make就不会自动取找文件依赖性,也就不会自动执行其后面所定义的命令。要执行后面定义的命令,就要在make命令后面明显的指出这个lable的名字。

make是如何工作的

当输入make命令后,

1.make会在当前目录下找名字为“Makefile”或“makefile”的文件

2.如果找到,他会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。

3.如果“edit”文件不存在,或是edit所依赖的后面的.o文件修改时间要比这个文件新,那么,他就会执行后面定义的命令来生成edit这个文件

4. 如果edit 所以依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到再根据规则生成.o文件

5.当然,你的C文件和H文件是存在的,于是make会生成.o文件,再用生成的.o文件生成最终文件edit

makefile中变量使用

在上面的例子中相同的字符串被使用了多次,如果我们的工程中需要新加入一个新的.o文件,那么我们需要在多个地方添加。

为了makefile的容易维护,在makefie中我们可以使用变量。makefile变量可以理解为C语言中的宏。

声明一个变量objects

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o

于是之前的例子可以被修改为:

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 
edit : $(objects)
    cc -o edit $(objects)

main.o : main.c defs.h
    cc -c main.c
kbd.o  : kbd.c defs.h command.h
    cc -c kbd.c
command.o :command.c defs.h command.h
    cc -c command.c
display.o : display.c defs.h buffer.h
    cc -c display.c
instert.o : insert.c defs.h buffer.h
    cc -c insert.c
search.o : search.c defs.h buffer.h
    cc -c search.c
files.o: files.c defs.h buffer.h command.h
    cc -c files.c
utils.o : utils.c defs.h
    cc -c utils.c

clean:
    rm edit $(objects)

如果有新的.o文件加入,我们只需要简单的修改一下objects变量就可以了。

让make自动推导

GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们没有必要去在每一个.o文件后面都写上类似命令,因为,make会自动识别,并自动推导命令。

只要make 看到一个.o文件,他就会自动的把.c文件加在依赖关系中。例如,如果make找到一个whatever.o 那么,whatever.c就会是whatever.o的依赖文件。并且cc -C whatever.c 也会被推导出来。

于是上面的makefile可以修改为如下:

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 
edit : $(objects)
cc -o edit $(objects)

main.o : defs.h
kbd.o  : defs.h command.h
command.o :defs.h command.h
display.o : defs.h buffer.h
instert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
clean:
    rm edit $(objects)

这种方法是make的一种隐晦规则

清空目标文件的规则

  一般的做法是

clean:
    rm edit $(objets)

更稳健的方式是

.PHONY: clean
clean:
    -rm edit $(objects)

 .PHONY 表示clean是一个伪目标,在rm前面加-的意思是,也许有些文件会出现问题,但不要管,继续后面的事。

clean 一般都是放在文件的最后。

Makefile总述

Makefile里有什么

makefile中主要包含了五个东西:显示规则、隐晦规则、变量定义、文件指示和注释

1.显示规则:

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

2.隐晦规则

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

3.变量的定义

在makefile中我们要定义一系列的变量,变量一般都是字符串,相当于C语言中的宏定义,当makefile执行时,其中的变量就会被扩展到相应的引用位置上。

4.文件指示

其中包括三个部分,一个是在makefile中引用另一个Makefile,就像C语言中的include 一样,另一个是指根据某些指定的makefile中的有效部分,就像C语言中的条件编译一样,还有就是定义一个多行命令。

5.注释

Makefile中只有行注释,和UNIX的shell脚本一样,其注释是用“#”,如果要在makefile中使用 # 那么按 \# 转义使用

makefile的文件名

默认情况下,make命令会在当前目录下按顺序找寻 GNUmakefile makefile Makefile文件,找到了解释这个文件。

引用其他的makefile

在Makefile中使用include 关键字可以把别的Makefile包含进来,这很像C语言的#include ,被包含的文件会原模原样的放在当前文件的包含位置。 include <filename>

filename可以是当前操作系统和shell的文件模式,在include前面 可以有一些空字符,但是不能以TAB键开始。

include foo.make *.mk $(bar)

等价于:

include foo.make a.mk b.mk c.mk e.mk f.mk

make命令开始时,会找寻include所指出的其他Makefile,并把其内容安置在当前的位。就好像C指令一样,如果文件都没有指定绝对路的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make 还会再下面的目录中寻找:

1.如果make执行时,“有-I”或者“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。

2.如果目录 <prefix>/include 存在的话,make也会去找。如果没有找到,make会生成一条警告信息,但不会立马出现致命错误。他会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或读取不到的文件,如果还是不行,make才会出现一条致命信息。如果想让make不理会哪些无法读取到的文件而继续执行,可以再include 前增加一个 “-”

环境变量 MAKEFILES

如果当前环境中定义了环境变量MAKEFILES,那么,make会把这个变量中的值做一个类似include 的动作。这个变量中的值是其它Makefile,用空格分开。他和include 不同的是,从这个环境变量中引入的Makefile的目标不会起作用,如果环境变量发生错误,make也不会理。

  尽量建议不要使用这个环境变量。

make的工作方式

1.读取所有的Makefile

2.读入被include的其他makefile

3.初始化文件中的变量

4.推导隐晦规则,并分析素所有规则。

5.为所有的目标文件创建依赖关系链

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

7.执行生成命令

书写规则

规则包括两个部分,依赖关系 和目标生成方法。

1,规则举例

foo.o : foo.c defs.h  #foo 模块

cc -c -g foo.c

看到这个例子,各位应该不会很陌生,前面说过,foo.o是我们的目标,foo.c和defs.h是目标所依赖的源文件,而只有一个命令

“cc -c -g foo.c” 

这个规则告诉我们两件事:

1.文件依赖关系,foo.o依赖于文件foo.c和文件defs.h的文件,如果foo.c和defs.h的文件日期要比foo.o的日期要新,或者foo.o不存在,那么发生依赖关系。

2.如何生成或者更新的foo.o文件,也就是这个cc命令,其说明了,如何生成foo.o这个文件。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值