从只有一个Makefile的单级Makefile开始。
对于一个稍大的项目或者说软件来说,源程序(.c文件或者是.h文件),以及源程序文件夹,绝对不只是一个文件或者源程序文件夹,想想你写的代码只有一个源程序或者程序文件夹还是什么时候。一个好的程序员,总是希望自己写的代码文件,清晰,一目了然,通过不同的文件夹,不用的名字就能大致看出该程序的功能。
当只有一个源程序文件的时候,比如main.h,main.c,这个时候,由于源程序文件少,我们可以手动对程序进行编译:gcc main.c -o main_exe。这个时候,手动编译程序还是很方便的。但是,如果程序有几十甚至几百几千个的时候,这个时候,通过gcc手动的对源程序进行编译的时候,就有困难了。另外,好的程序员会去考虑到程序的可移植性和程序文件之间的关系,我们总是希望把源程序拿过来直接编译然后就能运行,我们会把源程序放在不同的文件夹下。这样一来,对于手动编译程序就更加困难了。这个时候,Makefile优势就显现出来了。
下面以实例来说明Makefile究竟如何编写,
/*
*************************************
name:example-one.c
*************************************
*/
#include “example-one.h”
{
…….
……..
}
*************************************
name:example-one.h
养成每个.c源程序都有一个与之同名的.h
与之对应来做一些声明。
*************************************
*/
#include <>
#include <>
/*
*************************************
name:example-two.c
*************************************
*/
#include “example-two.h”
#include “example-one.h”
{
…….
……..
}
*************************************
name:example-two.h
养成每个.c源程序都有一个与之同名的.h
与之对应来做一些声明。
*************************************
*/
#include <>
#include <>
…..
…..
*************************************
name:main.c
*************************************
#include “example-two.h”
{
}
在这里我不讲Makefile的规则,对于这些规则,网上的关于Makefile的编写都大同小异,我主要讲讲Makefile的工作原理。
按照上述文件之间的关系不难看出,example-two.c由于使用了example-one.c的东西,那么当我们编译example-two.c的时候就需要example-one.c。
还是先来说下几个关键词
target:cond
按照Makefile的规则,target就是目标,然后cond就是要编译得到target目标所需要的条件。
其实在很多情况下,我们的Makefile可以只写出
%:%.o
这个规则就可以了。
以这个例子为例。虽然按照实际情况上来说,有个层次关系,main.o的编译需要example-two.c, example-two.h作为必要条件,同理,example-two.o需要example-one.h和example-one.c作为必要条件。
但是,你可以试试,这个例子的Makefile可以简化到如此简单:
OBJS := main.o example-one.o example-two.o
EXEC := test
$(EXEC):$(OBJS)
tab gcc –o $(EXEC) $(OBJS)
写好commamd之后,make就可以编译出程序了,绝对没问题。
Makefile其实也是一种脚本语言。他只需要知道编译成可执行程序EXEC所必须的目标文件OBJS有哪些(这里对于将目标文件.o文件,源文件 .h, .c文件同名很重要,所以要养成这种习惯会给变成带来很大的方便的)。
GNU 的make 工作时的执行步骤入下:
1、读入所有的Makefile。
2、读入被include 的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。
当make一旦知道可执行文件所需的目标文件.o文件之后,他发现要生成可执行文件需要哪些.o文件,他就会在你所指定的目录已经当前目录中查找,当他找不到某一.o文件的时候,就会启动隐含规则去试图生成.o文件。同样,当生成.o文件的时候就会去找相应的.c文件和.h文件。这才是这个例子会有如此简单的Makefile的真正原因。而Makefile的编写工作最终落实到你给出文件,让make去找文件。而本身源程序.c文件中的include也同时告诉Makefile,.c文件需要哪些.h条件,所以在由.c文件到.o文件的过程中可以由它自动来完成,不需要我们明确的显示的告诉他这些关系。
给个不恰当的比喻:.c .h文件相当于人,通过#include 已经extern 等血缘关系,在make之后,构成了家庭这种.o文件。
family.o: zhang.c wang.c zhang_son.h
所有的人都用过这种关系来构成家庭。
然后那么社区这种可执行文件是有家庭这种.o文件构成的。那么在组装可执行文件这一阶段只需要列出该社区的所有的家庭,于是也就自动完成了社区的组建。
community:family_one.o family_two.o…
总之,在组装可执行程序的规则中,要列出所需要的所有的.o文件。
版权申明:
转载文章请注明原文出处http://blog.csdn.net/feiyinzilgd/archive/2010/02/07/5297161.aspx
并请联系谭海燕本人或者前往谭海燕个人主页留言