makefile实例讲解.docx

上传人:b****0 文档编号:9847741 上传时间:2023-05-21 格式:DOCX 页数:24 大小:21.93KB
下载 相关 举报
makefile实例讲解.docx_第1页
第1页 / 共24页
makefile实例讲解.docx_第2页
第2页 / 共24页
makefile实例讲解.docx_第3页
第3页 / 共24页
makefile实例讲解.docx_第4页
第4页 / 共24页
makefile实例讲解.docx_第5页
第5页 / 共24页
makefile实例讲解.docx_第6页
第6页 / 共24页
makefile实例讲解.docx_第7页
第7页 / 共24页
makefile实例讲解.docx_第8页
第8页 / 共24页
makefile实例讲解.docx_第9页
第9页 / 共24页
makefile实例讲解.docx_第10页
第10页 / 共24页
makefile实例讲解.docx_第11页
第11页 / 共24页
makefile实例讲解.docx_第12页
第12页 / 共24页
makefile实例讲解.docx_第13页
第13页 / 共24页
makefile实例讲解.docx_第14页
第14页 / 共24页
makefile实例讲解.docx_第15页
第15页 / 共24页
makefile实例讲解.docx_第16页
第16页 / 共24页
makefile实例讲解.docx_第17页
第17页 / 共24页
makefile实例讲解.docx_第18页
第18页 / 共24页
makefile实例讲解.docx_第19页
第19页 / 共24页
makefile实例讲解.docx_第20页
第20页 / 共24页
亲,该文档总共24页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

makefile实例讲解.docx

《makefile实例讲解.docx》由会员分享,可在线阅读,更多相关《makefile实例讲解.docx(24页珍藏版)》请在冰点文库上搜索。

makefile实例讲解.docx

makefile实例讲解

Makefile学习笔记:

为什么要学习makefile:

工作经验让我认识到会不会写makefile从一个侧面说明了一个人是否有完成大型工程的能力,makefile关系到整个工程的编译规则,一个工程的文件不计其数,其按类型,功能,模块分别放在不同的目录下,makefile定义了一些规则来指定,哪些文件需要先编译,哪些文件需要重新编译,甚至进行更复杂的功能操作,因为makefile就像一个shell脚本一样,其中也可以执行操作系统命令。

而make只是一个命令工具,是一个解释makefile中的指令的命令工具,一般来说IDE即集成开发环境都有这个命令。

Makefile的环境:

我是在linux下进行的实验linux系列下,我用的是ubuntu,当然你可以用redhat红旗后其他,我想都没有什么问题的。

在做实验的时候我会做一些linux写的c/c++例子来演示,以加深理解。

关于程序的编译和链接:

一般来说,c或者是c++,首先把源文件(*.c或*.cpp)编译成为中间代码文件,这个中间代码文件在windows下是*.obj文件在linux或unix是*.o文件即objectfile目标文件这个动作就叫做编译,即把源文件编译成目标文件的过程就叫做编译(compile)。

这以后,再把大量的*.obj或*.o目标文件合成一个可以执行的文件,这个工程就叫做链接link。

编译时,主要是检查程序的语法是否正确,函数,变量是否都有声明。

至于链接呢,主要是链接函数,和全局变量。

一.Makefile的规则

Target:

prerequisites

Command

Target就是一个目标文件,可以使obj或是可执行文件还可以是一个标签label,关于标签label会在下面的文目标中讲解。

所以我们现在只关注obj和可执行文件即可,其实大部分还都是obj文件,或许可执行文件就只有一个。

Prerequisites是先决条件的意识,其实在这里只是依赖的意思,prerequisites在这里是生成target的所需要的文件或目标。

Command就是make需要执行的命令的,任意的shell的命令,如果prerequisites中有一个以上的文件比target文件要新的话吗,command所定义的命令的就会被执行。

这就是makefile的规则,也是makefile中最核心的东西。

一个例子:

这个makefile有六个源文件和六个头文件分别是:

func1.cfunc2.cfunc3.cfunc4.cfunc5.cmain.c

head1.hhead2.hhead3.hhead4.hhead5.hhead.h

上面的c源文件分别会用到其下的头文件各个文件的内容分别是:

func1.c文件

#include"head.h"

#include"head1.h"

voidf1()

{

structstudent1stu;

stu.id=10101;

strcpy(stu.name,"ygt1");

stu.sex='m';

printf("id=%d\tname=%s\tsex=%c\n",stu.id,stu.name,stu.sex);

}

func2.c文件

#include"head.h"

#include"head2.h"

voidf2()

{

structstudent2stu;

stu.id=10102;

strcpy(stu.name,"ygt2");

stu.sex='m';

printf("id=%d\tname=%s\tsex=%c\n",stu.id,stu.name,stu.sex);

}

func3.c文件

#include"head.h"

#include"head3.h"

voidf3()

{

structstudent3stu;

stu.id=10103;

strcpy(stu.name,"ygt3");

stu.sex='m';

printf("id=%d\tname=%s\tsex=%c\n",stu.id,stu.name,stu.sex);

}

func4.c文件

#include"head.h"

#include"head4.h"

voidf4()

{

structstudent4stu;

stu.id=10104;

strcpy(stu.name,"ygt4");

stu.sex='m';

printf("id=%d\tname=%s\tsex=%c\n",stu.id,stu.name,stu.sex);

}

func5.c文件

#include"head.h"

#include"head5.h"

voidf5()

{

structstudent5stu;

stu.id=10105;

strcpy(stu.name,"ygt5");

stu.sex='m';

printf("id=%d\tname=%s\tsex=%c\n",stu.id,stu.name,stu.sex);

}

main.c文件

#include"head.h"

externvoidf1();

externvoidf2();

externvoidf3();

externvoidf4();

externvoidf5();

intmain()

{

f1();

f2();

f3();

f4();

f5();

printf("theend\n");

return0;

}

以上是这个工程的的所有源文件及其代码

head1.h头文件

structstudent1

{

intid;

charname[20];

charsex;

};

head2.h头文件

structstudent2

{

intid;

charname[20];

charsex;

};

head3.h头文件

structstudent3

{

intid;

charname[20];

charsex;

};

head1.h头文件

structstudent3

{

intid;

charname[20];

charsex;

};

head4.h头文件

structstudent4

{

intid;

charname[20];

charsex;

};

head51.h头文件

structstudent5

{

intid;

charname[20];

charsex;

};

head.h头文件

#include

#include

#include

以上是头文件的内容

以上文件都准备好后就要开始写makefile文件了

 

Makefile文件的可以这么写:

 

exefile:

main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

gcc-oexefilemain.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

main.o:

main.chead.h

gcc-cmain.c

func1.o:

func1.chead.hhead1.h

gcc-cfunc1.c

func2.o:

func2.chead.hhead2.h

gcc-cfunc2.c

func3.o:

func3.chead.hhead3.h

gcc-cfunc3.c

func4.o:

func4.chead.hhead4.h

gcc-cfunc4.c

func5.o:

func5.chead.hhead5.h

gcc-cfunc5.c

 

clean:

rm-f*.oexefile

在这个makefile中蓝色的就是目标文件或可执行文件目标文件时那些*.o文件,可执行文件就是exefile文件,它是最终可以执行的文件。

依赖文件就是那些*.c和*.h文件。

每一个*.o文件都有一组依赖文件,*.o文件就是靠这些依赖文件生成。

而生成的这些*.o文件又都是exefile可执行文件的依赖文件,他们生成exefile可执行文件。

依赖关系其实就是说明了目标文件是由哪些文件生成的,换言之,就是目标文件是由哪些文件更新的。

定义好依赖关系下一行就是make执行的命令,这个命令定义了操作系统如何生成这些目标文件的。

命令行开始一定要以tab键开头。

其执行过程就是make会比较target文件和prerequisites文件的修改日期,如果prerequisites文件的日期比target文件的日期要新,或者target不存在的话,make就会执行后续定义的命令。

讲解:

exefile:

main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

gcc-oexefilemain.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

exefile依赖main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o这些*.o文件,也即是说exefile就是开这些文件生成的。

一开始这些*.o文件是不存在的,那么make就会往下执行语句,而暂时先不执行gcc-omainmain.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o这句命令。

main.o:

main.chead.h

gcc-cmain.c

main.o依赖main.chead.h这两个文件执行其命令生成main.o目标文件,指着往下执行。

func1.o:

func1.chead.hhead1.h

gcc-cfunc1.c

同main.o的执行。

func2.o:

func2.chead.hhead2.h

gcc-cfunc2.c

同main.o的执行。

func3.o:

func3.chead.hhead3.h

gcc-cfunc3.c

同main.o的执行。

func4.o:

func4.chead.hhead4.h

gcc-cfunc4.c

同main.o的执行。

func5.o:

func5.chead.hhead5.h

gcc-cfunc5.c

同main.o的执行。

当这些*.o文件都别生成了后make就会执行第一个依赖和第一个依赖之后的命令

exefile:

main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

gcc-oexefilemain.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

最终生成exefile之可行文件。

clean:

rm-f*.oexefile

clean后面没有依赖文件,make是不会执行其后的命令的,只能makeclean显视的执行。

这句就是伪命令,就是做一些清理,把生成的目标文件*.o文件和exefile删掉。

Make后执行结果:

[yanggentao@wkpmfile]$makeclean

rm-f*.oexefile

[yanggentao@wkpmfile]$make

gcc-cmain.c

gcc-cfunc1.c

gcc-cfunc2.c

gcc-cfunc3.c

gcc-cfunc4.c

gcc-cfunc5.c

gcc-omainmain.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

[yanggentao@wkpmfile]$

Makeclean后执行结果:

[yanggentao@wkpmfile]$makeclean

rm-f*.oexefile

[yanggentao@wkpmfile]$

根据makefile的依赖规则我们还可以这样写,至于为什么这样写,我们先且不说。

exefile:

main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

gcc-oexefilemain.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

main.o:

main.c

gcc-cmain.c

func1.o:

func1.c

gcc-cfunc1.c

func2.o:

func2.c

gcc-cfunc2.c

func3.o:

func3.c

gcc-cfunc3.c

func4.o:

func4.c

gcc-cfunc4.c

func5.o:

func5.c

gcc-cfunc5.c

clean:

rm-f*.oexefile

这样写是把头文件都给去掉了,这样也对的,makefile的隐式规则会自动找这些在文件里包含的头文件的。

其实Makefile中的命令就像是shell里一样可以使用变量

二.Makefile中使用变量

Makefile中的变量就像是c语言的中宏一样

怎样定义变量呢?

我们在makefile最上面定义一个变量

OBJS=main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

引用变量$(OBJS)这就等价于main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o就像宏一样的会被替换掉。

所以我们的makefile可以这样写了:

OBJS=main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

exefile:

$(OBJS)

gcc-oexefile$(OBJS)

main.o:

main.c

gcc-cmain.c

func1.o:

func1.c

gcc-cfunc1.c

func2.o:

func2.c

gcc-cfunc2.c

func3.o:

func3.c

gcc-cfunc3.c

func4.o:

func4.c

gcc-cfunc4.c

func5.o:

func5.c

gcc-cfunc5.c

clean:

rm-f$(OBJS)exefile

这样写很方便,如果你想在这个工程里面加一个文件的话就不会很麻烦。

三.让make自动推导

Gnu的make功能很强大他可以自动推导文件及文件的依赖关系后面的命令所以我们没有必要去为*.O文件都写出其命令。

只要make看到一个*.o文件,它就会自动的吧*.c文件加到依赖关系中,如果make找到一个func2.o那么func2.c就会使func2.o的依赖文件。

并且gcc–cfunc2.c也会被推导出来。

所以我们的makefile就会简单多了:

我们还可以这样写:

OBJS=main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

exefile:

$(OBJS)

gcc-oexefile$(OBJS)

clean:

rm-f$(OBJS)exefile

有时候我们会这样写:

OBJS=main.ofunc1.ofunc2.ofunc3.ofunc4.ofunc5.o

exefile:

$(OBJS)

gcc-oexefile$(OBJS)

.PHONY:

clean

clean:

rm-f$(OBJS)exefile

.PHONY:

clean是声明一下clean是一个伪命令。

到这里makefile的基本东西已经讲完了。

还有很多细节,下面来看一下。

四.Makefile的5个内容

1.显示规则

2.隐晦规则

3.变量的定义

4.文件指示

5.注释

1.显示规则:

就是显示的在命令行中写出目标文件的依赖关系

2.隐晦规则:

就是利用make的自动推导的功能

3.变量的定义:

就变量的宏替换

4.文件指示:

其中包括三部分的内容,一个是在一个makefile中引用另一个makefile,就像c语言中的include一样;另一个是根据某些情况指定makefile中的有效部分,就像c语言的预编译#ifdef一样;还有一个就是定义一个多行的命令。

5.注释:

只有行注释用#号字符注释如果你的makefile中用到了#你可以用“\#“转义

Makefile的文件名默认会找这三个文件GNUmakefile,makefile和Makefile

当然你也可以任意起名字比如linuxmakefilemymakefile等但是如果要用的话,那么你就要指定它这样用make–flinuxmakefile或make–fmymakefile

引用其他的makefile

Makefile中也有include命令,这个命令就像cc++里的#include关键字一样包含

Include的语法是

Include

伪目标:

先前的一个例子:

Clean:

Rm–f*.oexefile

Clean就是一个伪目标因为呢,clean并不是一个文件只是一个标签,所以make无法生成它的依赖关系和决定是否要执行它的命令,所以呢我们只能通过显示的指明这个目标才能让其生效。

当然为目标的取名不能喝文件名同名,不然就失去了为目标的意义了。

所以我们可以用.PHONY来显示的指明一个伪目标向make说明不管是否有这个文件,这个目标就是伪目标。

.PHONY:

clean

Clean:

Rm–f*.o

伪目标没有依赖关系但是我们可以为他指定依赖文件。

例子:

这个例子可以生成三个可执行文件

先来看:

在linux下创建toucha.cb.cc.cmain1.cmain2.cmain3.ca.hb.hc.hmain.h执行此命令就会创建好所需要的文件,每个文件内容如下:

a.c文件

#include"main.h"

#include"a.h"

voidfa()

{

structstudentastud;

stud.id=10101;

strcpy(stud.name,"a.c");

stud.sex='f';

printf("studenta-->id=%d\tname=%s\tsex=%c\n",stud.id,stud.name,stud.sex);

}

b.c文件

#include"main.h"

#include"b.h"

voidfb()

{

structstudentbstud;

stud.id=10101;

strcpy(stud.name,"b.c");

stud.sex='f';

printf("studentb-->id=%d\tname=%s\tsex=%c\n",stud.id,stud.name,stud.sex);

}

c.c文件

#include"main.h"

#include"c.h"

voidfc()

{

structstudentcstud;

stud.id=10101;

strcpy(stud.name,"c.c");

stud.sex='f';

printf("studentc-->id=%d\tname=%s\tsex=%c\n",stud.id,stud.name,stud.sex);

}

main1.c文件

#include"main.h"

externvoidfa();

externvoidfb();

externvoidfc();

intmain()

{

fa();

//fb();

//fc();

printf("inthemain1\n");

return0;

}

main2.c文件

#include"main.h"

externvoidfa();

externvoidfb();

externvoidfc();

intmain()

{

fa();

fb();

fc();

printf("inthemain2\n");

return0;

}

main3.c文件

#include"main.h"

externvoidfa();

externvoidfb();

externvoidfc();

intmain()

{

fa();

fb();

fc();

printf("inthemain3\n");

return0;

}

main.h文件

#include

#include

#include

a.h文件

structstudenta

{

intid;

charname[20];

charsex;

};

b.h文件

structstudentb

{

intid;

charname[20];

charsex;

};

c.h文件

structstudentc

{

intid;

charname[20];

charsex;

};

我们的makefile先这样写:

main1:

main1.oa.ob.oc.o

gcc-omain1main1.oa.ob.oc.o

main2:

main2.oa.ob.oc.o

gcc-omain2main2.oa.ob.oc.o

main3:

main3.oa.ob.oc.o

gcc-omain3main3.oa.ob.oc.o

看看执行结果是什么why?

执行结果只执行了第一个生成了main1why;

正确的写法:

all:

main1main2main3

.PHONY:

all

main1:

main1

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2