makefile的编写PPT格式课件下载.ppt
- 文档编号:1226645
- 上传时间:2023-04-30
- 格式:PPT
- 页数:39
- 大小:701KB
makefile的编写PPT格式课件下载.ppt
《makefile的编写PPT格式课件下载.ppt》由会员分享,可在线阅读,更多相关《makefile的编写PPT格式课件下载.ppt(39页珍藏版)》请在冰点文库上搜索。
,8.1.2关于程序的编译和链接,无论是C、C+,首先要把源文件编译成中间代码文件,在Windows下是.obj文件,UNIX下是.o文件,即目标文件,这个动作叫做编译(compile)。
然后再把大量的目标文件链接成执行文件,这个动作叫作链接(link)。
编译时,编译器检查语法,函数与变量的声明是否正确。
对于声明,通常需要你告诉编译器头文件所在的位置(头文件中应该只是声明,而定义应该放在源文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。
一般来说,每个源文件可以生成一个中间目标文件(.o文件或是.obj文件)。
关于程序的编译和链接,链接时,主要是找到函数和全局变量的定义。
链接器并不管函数所在的源文件,只管函数的中间目标文件(ObjectFile)。
在大多数时候,由于源文件太多,编译生成的目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(LibraryFile),也就是.lib文件,在UNIX下,是ArchiveFile,也就是.a文件或.so下面是一个包含三个文件的工程,8.1.3准备文件file1.c,#include#includefile2.hintmain()printf(printfile1n);
File2Print();
return0;
返回,准备文件file2.c,#includefile2.hvoidFile2Print()printf(Printfile2n);
返回,准备文件file2.h,#ifndefFILE2_H_#defineFILE2_H_#includevoidFile2Print();
#endif,返回,8.1.4Makefile里的主要规则,target.:
mand.target是一个目标文件,可以是ObjectFile,也可以是执行文件。
还可以是一个标签(伪目标)。
prerequisites是要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。
(任意的Shell命令)文件的依赖关系,也就是说,target是需要生成的一个或多个文件,它们依赖于prerequisites.中列出的文件,通过执行command来生成target.。
一个规则可以有多个命令行,每一条命令占一行。
注意:
每一个命令行必须以Tab字符开始,Tab字符告诉make此行是一个命令行。
make按照命令完成相应的动作。
这也是书写Makefile中容易产生,而且比较隐蔽的错误。
这就是Makefile的规则,也是Makefile中最核心的内容。
helloworld:
file1.ofile2.ogccfile1.ofile2.o-ohelloworldfile1.o:
file1.cfile2.hgcc-cfile1.c-ofile1.ofile2.o:
file2.cfile2.hgcc-cfile2.c-ofile2.oclean:
rm-rf*.ohelloworld,编写Makefile文件,详细解读Makefile文件,helloworld:
file1.ofile2.ogccfile1.ofile2.o-ohelloworldhelloworld依赖file1.ofile2.o两个文件编译出helloworld可执行文件。
-o表示指定的目标文件名。
若file1.o和file2.o都存在,但是其中一个比helloworld新或helloworld不存在时,执行下面的gcc命令。
若file1.o和file2.o有任意一个不存在,假设是file1.o,会先找到file1.o的生成关系,生成file1.o后,再执行下面的gcc命令。
详细解读Makefile文件(续),file1.o:
file1.cfile2.hgcc-cfile1.c-ofile1.ofile1.o依赖file1.c和file2.h这两个文件,编译出file1.o文件。
若依赖文件中有任意一个文件不存在或比file1.o新,都会重新执行下面的gcc命令。
-c表示gcc只把给它的文件编译成.o文件,用源码文件的文件名命名但把其后缀由“.c”变成“.o”。
在这句中,可以省略-ofile1.o,编译器默认生成file1.o文件,这就是-c的作用。
file2.o:
file2.cfile2.hgcc-cfile2.c-ofile2.o这两句的功能同上。
返回,详细解读Makefile文件(续),clean:
rm-rf*.ohelloworld#当用户输入makeclean命令时,会执行rm指令,其功能是删除*.o和helloworld文件。
写好Makefile文件,在命令行中直接键入make命令,就会执行Makefile中的内容了,返回,假设一个工程有3个头文件,和8个源文件,我们按照那三个规则写出的makefile应该是下面的这个样子的。
edit:
main.okbd.ocommand.odisplay.oinsert.osearch.ofiles.outils.occ-oeditmain.okbd.ocommand.odisplay.oinsert.osearch.ofiles.outils.omain.o:
main.cdefs.hcc-cmain.ckbd.o:
kbd.cdefs.hcommand.hcc-ckbd.ccommand.o:
command.cdefs.hcommand.hcc-ccommand.c,display.o:
display.cdefs.hbuffer.hcc-cdisplay.cinsert.o:
insert.cdefs.hbuffer.hcc-cinsert.csearch.o:
search.cdefs.hbuffer.hcc-csearch.cfiles.o:
files.cdefs.hbuffer.hcommand.hcc-cfiles.cutils.o:
utils.cdefs.hcc-cutils.cclean:
rmeditmain.okbd.ocommand.odisplay.oinsert.osearch.ofiles.outils.o,在这个makefile中,目标文件(target)包含:
执行文件edit和中间目标文件(*.o)。
依赖文件(prerequisites)就是冒号后面的那些.c文件和.h文件。
每一个.o文件都有一组依赖文件,而这些.o文件又是执行文件edit的依赖文件。
依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。
make如何工作,在默认的方式下,也就是我们只输入make命令。
那么:
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、默认的情况下,make执行的是Makefile中的第一个规则。
此规则的第一个目标称之为“最终目的”或者“终极目标”。
在上面的例子中,它会找文件中的第一个目标文件(target),即“edit”这个文件,并把这个文件作为最终的目标文件。
3、如果edit文件不存在,或是edit所依赖的后面的.o文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
4、如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为该.o文件的依赖规则,如果找到则再根据那一个规则生成.o文件。
(这有点像一个栈的过程)5、前提你的.c文件和.h文件是存在,make如何工作,这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
通过上述分析,我们知道,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。
即命令“makeclean”,以此来清除所有的目标文件,以便重编译。
使用变量,取得变量值的方式:
$(变量名)或$变量名定义变量=使用时展开:
=定义时即展开(只能使用已经定义好的变量)+=变量追加?
=若未定义则定义,若已定义则不执行此定义例如:
objects=main.okbd.ocommand.odisplay.oinsert.osearch.ofiles.outils.o于是,我们就可以很方便地在我们的makefile中以“$(objects)”的方式来使用这个变量了,变量基础,objects=program.ofoo.outils.oprogram:
$(objects)cc-oprogram$(objects)或者:
cc$-o$和$属于自动化变量$表示规则中的目标文件集。
在模式规则中,如果有多个目标,那么,$就是匹配于目标中模式定义的集合。
这里是program$所有的依赖目标的集合。
以空格分隔。
如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
这里是$(objects)$(objects):
defs.h变量会在使用它的地方精确地展开,就像C/C+中的宏一样,Makefile里使用变量,OBJS=file1.ofile2.oCC=gccCFLAGS=-Wall-Og-Wall:
输出所有的警告信息;
-O:
在编译时进行优化;
-g:
表示编译debug版本。
helloworld:
$(OBJS)$(CC)$(OBJS)-ohelloworldfile1.o:
file1.cfile2.h$(CC)$(CFLAGS)-cfile1.c-ofile1.ofile2.o:
file2.cfile2.h$(CC)$(CFLAGS)-cfile2.c-ofile2.oclean:
rm-rf*.ohelloworld,返回,自动推导-隐晦规则?
GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个.o文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。
只要make看到一个.o文件,它就会自动的把.c文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。
并且gcc-cwhatever.c也会被推导出来,于是,我们的makefile再也不用写得这么复杂。
我们的是新的makefile又出炉了。
自动推导-隐晦规则?
前面的makefile可以这么写:
objects=main.okbd.ocommand.odisplay.oinsert.osearch.ofiles.outils.oedit:
$(objects)cc-oedit$(objects)main.o:
defs.hkbd.o:
defs.hcommand.hcommand.o:
defs.hcommand.hdisplay.o:
defs.hbuffer.hinsert.o:
defs.hbuffer.hsearch.o:
defs.hbuffer.hfiles.o:
defs.hbuffer.hcommand.hutils.o:
defs.h.PHONY:
cleanclean:
rmedit$(objects),Make又是如何实现自动推导的呢?
在隐含规则中的命令中,基本上都是使用了一些预先设置的变量。
你可以在你的makefile中改变这些变量的值。
比如,编译C程序的隐含规则的命令是:
$(CC)c$(CFLAGS)$(CPPFLAGS)Make默认的编译命令是“cc”,如果你把变量“$(CC)”重定义成“gcc”,把变量“$(CFLAGS)”重定义成“-g”,那么,隐含规则中的命令全部会以“gccc-g$(CPPFLAGS)”的样子来执行了。
我们可以把隐含规则中使用的变量分成两种:
一种是命令相关的,如“CC”;
一种是参数相的关,如“CFLAGS”。
下面是C/C+隐含规则中会用到的变量:
关于命令的变量:
AR函数库打包程序。
默认命令是“ar”。
AS汇编语言编译程序。
默认命令是“as”。
CXXC+语言编译程序。
默认命令是“g+”。
CCC语言编译程序。
默认命令是“cc”。
CPPC程序的预处理器(输出是标准输出设备)。
默认命令是$(CC)E关于命令参数的变量。
下面的这些变量都是相关上面的命令的参数。
如果没有指明其默认值,那么其默认值都是空。
ARFLAGS函数库打包程序AR命令的参数。
默认值是“rv”。
ASFLAGS汇编语言编译器参数。
(当明显地调用“.s”或“.S”文件时)CFLAGSC语言编译器参数。
CXXFLAGSC+语言编译器参数。
LDFLAGS链接器参数。
(例如:
LDFLAGS+=-L./.ltest)CPPFLAGSC预处理器参数。
(C和Fortran编译器也会用到)。
另类Makefile?
如何把重复的buffer.h去掉?
这个对于make来说很容易,它提供了自动推导命令和文件的功能呢?
来看看最新风格的makefile吧。
objects=main.okbd.ocommand.odisplay.oinsert.osearch.ofiles.outils.oedit:
$(objects)cc-oedit$(objects)$(objects):
defs.hkbd.ocommand.ofiles.o:
command.hdisplay.oinsert.osearch.ofiles.o:
buffer.h.PHONY:
cleanclean:
rmedit$(objects),不推荐这种风格:
一是文件的依赖关系看不清楚:
二是如果文件一多,要加入几个新的.o文件,那就理不清楚了,清空目标文件的规则,每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。
clean:
rmedit$(objects)更为稳健的做法是:
.PHONY:
-rmedit$(objects).PHONY意思表示clean是一个“伪目标”。
而在命令前面加了一个小减号的意思就是,即便该命令执行出错,make也不管。
对于rm命令,意思是也许某些文件出现问题,但不要管,继续做后面的事。
当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标。
不成文的规矩是“clean从来都是放在文件的最后”。
文件名,二、Makefile的文件名默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。
在这三个文件名中,最好使用“Makefile”这个文件名,因为,这个文件名第一个字符为大写,这样有一种显目的感觉。
最好不要用“GNUmakefile”,这个文件是GNU的make识别的。
有另外一些make只对全小写的“makefile”文件名敏感,但是基本上来说,大多数的make都支持“makefile”和“Makefile”这两种默认文件名。
当然,你可以使用别的文件名来书写Makefile,比如:
“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“-file”参数,如:
make-fMake.Linux或make-fileMake.AIX。
引用其它的Makefile,在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。
include的语法是:
includefilename可以是当前操作系统Shell的文件模式(可以保含路径和通配符)在include前面可以有一些空字符,但是绝不能是Tab键开始。
include和可以用一个或多个空格隔开。
举个例子,你有这样几个Makefile:
a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了e.mk和f.mk,那么,下面的语句:
includefoo.make*.mk$(bar),书写规则,规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。
一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。
如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。
make所完成的也就是这个目标。
语法规则,targets:
prerequisitescommand.targets是文件名,以空格分开,可以使用通配符。
一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。
command是命令行,如果其不与“targetprerequisites”在一行,那么,必须以Tab键开头,如果和prerequisites在一行,那么可以用分号做为分隔。
prerequisites也就是目标所依赖的文件(或依赖目标)。
如果其中的某个文件要比目标文件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。
这个在前面已经讲过了。
如果命令太长,你可以使用反斜框()作为换行符。
make对一行上有多少个字符没有限制。
规则告诉make两件事,文件的依赖关系和如何成成目标文件。
一般来说,make会以Linux的标准Shell,也就是/bin/bash来执行命令。
伪目标,前面我们看到如下规则,通过.PHONY告诉make,clean是个伪目标.PHONY:
-rmedit$(objects)“伪目标”并不是一个文件,只是一个标签,所以通常,make无法生成它的依赖关系和决定它是否要执行,只能通过显示地指明这个“目标”才能让其生效。
“伪目标”的取名不能和文件名重名。
为了避免和文件重名的这种情况,可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”伪目标一般没有依赖的文件,但也可以为伪目标指定所依赖的文件。
伪目标同样可以作为“默认目标”,只要将其放在第一个。
如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:
all:
prog1prog2prog3.PHONY:
allprog1:
prog1.outils.occ-oprog1prog1.outils.oprog2:
prog2.occ-oprog2prog2.oprog3:
prog3.osort.outils.occ-oprog3prog3.osort.outils.o我们知道,Makefile中的第一个目标会被作为其默认目标。
我们声明了一个“all”的伪目标,其依赖于其它三个目标。
执行make时,目标“all”被作为终极目标。
为了完成对它的更新,make会创建(不存在)或者重建(已存在)目标“all”的所有依赖文件(prog1、prog2和prog3)。
这就达到了我们一口气生成多个目标的目的。
“.PHONY:
all”声明了“all”这个目标为“伪目标”。
从前面的例子我们可以看出,目标可以成为依赖。
伪目标同样也可成为依赖。
看下面的例子:
cleanallcleanobjcleandiffcleanall:
cleanobjcleandiffrmprogramcleanobj:
rm*.ocleandiff:
rm*.diff“makeclean”将清除所有要被清除的文件。
“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。
我们可以输入“makecleanall”和“makecleanobj”和“makecleandiff”命令来达到清除不同种类文件的目的。
静态模式,静态模式规则是这样一个规则:
规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。
静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。
我们还是先来看一下语法:
:
.targets定义了一系列的目标文件,可以有通配符。
是目标的一个集合。
目标中的%定义表示对文件名的匹配target-parrtern是指明了targets的模式,也就是的目标集模式。
如果“%”定义在目标中,那么,目标中的“%”的值决定了依赖目标中的“%”的值prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。
静态模式,举个例子:
如果我们的定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们的定义成“%.c”,意思是对所形成的目标集进行二次定义,其计算方法是,取模式中的“%”(也就是去掉了.o这个结尾),并为其加上.c这个结尾,形成的新集合。
所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“”进行转义,来标明真实的“%”字符。
看一个例子:
objects=foo.obar.oall:
$(objects)$(objects):
%.o:
%.c$(CC)-c$(CFLAGS)$-o$例子中,指明了我们的目标从$(object)中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“f
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- makefile 编写
![提示](https://static.bingdoc.com/images/bang_tan.gif)