luqingfei@C++

为中华之崛起而崛起!
兼听则明,偏听则暗。

什么是Makefile

 

什么是makefile?或许很多Windows的程序员都不知道这个东西,因为那些WindowsIDE都为你做了这个功作,但是作为一个好的和专业的程序员,makefile还是要懂的。这就好像现在有许多的所见即所得的网页制作工具,但如果你想成为一个专业网页开发人员,你还是要了解HTML的标识的含义的,当然还有其它的比如CSSJavaScript等等等等。

 

makefile关系到整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

 

makefile带来的好处就是——自动化编译,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:DelphimakeVisual C++nmakeLinuxGNUmake。可见,makefile都成为了一种在工程方面的编译方法。

 

不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章。

 

 

关于程序的编译和连接

在此,先说说关于程序编译的一些规范和方法,一般来说,无论是CC++,还是pas,首先要把源文件编译成中间的代码文件,在Windows下也就是.obj文件,UNIX下是.o文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫做链接(link)。

 

编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。

 

链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数的时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是.lib文件,在UNIX下,是Archive File,也就是.a文件。

 

总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error)。在VC下,这种错误一般是:Link 2001错误,意思就是说,链接器未能找到函数的实现。你需要指定函数的Object File

 

 

言归正传。

 

Makefile介绍

make命令执行时,需要一个Makefile文件,以告诉make命令要怎么样的去编译和链接程序。

 

Makefile规则:

规则包含两个部分,一个是依赖关系,一个是生成目标的方法。

 

target … : prerequisites…

command

目标:先决条件

命令

 

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

prerequisites 就是,要生成那个target所需要的文件或目标。

command 也就是make需要执行的命令。(任意的Shell命令)

 

这是一个文件的依赖文件,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

 

Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make所完成的也就是这个目标。

 

 

一个示例:一个工程只包含两个文件,一个汇编源码文件*.asm,一个资源文件.rc。注:这是我学习Win32汇编程序如果定义菜单的例子。

NAME = Menu

OBJS = $(NAME).obj

RES = $(NAME).res

 

LINK_FLAG = /subsystem:windows

ML_FLAG = /c /coff

 

$(NAME).exe: $(OBJS) $(RES)

       Link $(LINK_FLAG) $(OBJS) $(RES)

 

.asm.obj:

       ml $(ML_FLAG) $<

.rc.res:

       rc $<

 

clean:

       del *.obj

       del *.res

 

make是如何工作的

在默认的方式下,也就是我们只键入make命令。那么,

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

2,如果找到,它会找文件中的每一个目标文件(target),并把这个文件作为最终的目标文件。比如是XXX,一般它是一个可执行文件。

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

4,如果XXX所依赖的YYY文件存在,那么make会在当前文件中找目标为YYY文件的依赖性,如果找到则再根据那一个规则生成YYY文件。

5,当然,你的C文件和H文件都是存在的,于是make会生成YYY文件,然后再用YYY文件生成make的终极任务,也就是执行文件XXX了。

 

这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找到了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

 

通过上述分析,我们知道,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显式让make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。

 

于是在我们编程中,如果这个工程已经被编译过了,当我们修改了其中一个源文件,比如file.c,那么根据我们的依赖性,我们的目标file.obj会被重编译(也就是在这个依赖性关系后面所定义的命令),于是file.obj的文件也是最新的啦,于file.obj的文件修改时间要比最终的可执行文件XXX要新,所以XXX也会被重新链接了。

 

 

makefile中使用变量

为了makefile的易维护,在makefile中我们可以使用变量。

makefile的变量也就是一个字符串,理解成C语言的宏可能会更好一些。

比如,我们声明一个变量,叫OBJS.

makefile一开始就这样定义:

OBJS = 1.obj 2.obj 3.obj

于是,我们就可以很方便地在我们的makefile中以“$(OBJS)”的方式来使用这个变量了。

 

 

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

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

2、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。

3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。

4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些尾部指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。

5、注释。Makefile中只有行注释,和UNIXShell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜杠进行转义,如:“\#”。

 

 

先就整理到这里,不敢再往下看了,内容太多了,先有个概念,以后遇到问题再看。

posted on 2010-08-27 15:45 luqingfei 阅读(1449) 评论(0)  编辑 收藏 引用 所属分类: C++基础


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

留言簿(6)

随笔分类(109)

随笔档案(105)

Blogers

Game

Life

NodeJs

Python

Useful Webs

大牛

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜