陈皓专栏 【空谷幽兰,心如皓月】

芝兰生于深谷,不以无人而不芳;君子修道立德,不为困穷而改节。

用户操作
[即时聊天] [发私信] [加为好友]
陈皓ID:haoel
484932次访问,排名97好友47人,关注者69
芝兰生于空谷,不以无人而不芳;君子修道立德,不为困穷而改节。
haoel的文章
原创 71 篇
翻译 0 篇
转载 0 篇
评论 1052 篇
陈皓的公告
Email & MSN
haoel@hotmail.com
最近评论
liuxi:LS 两个command都是命令的意思 例如 cc -o test.o -c -g test.c这样的命令.
targets : prerequisites ; command
command
这个的意思是命令你可以选择写在先决条件(prerequisites)的后面用分号隔开;也可以另起一行用tab开始些命令。
figoshen:楼上的,楼主的程序我跑了没有问题,你说的的多加(int*)是问题我觉得加不加都一样了
silvervi:大哥,文章有错误

在VS 2005里面加了断点专门跑了一下,对照局部变量里面虚函数表的实际地址,错误跟我之前想的一样,少了一次解引用

正确的应该如下

cout << "虚函数表地址:" << (int *)*(int *)(&b) << endl;

cout &……
miansha:走过留名

谢谢LZ,学习并谨记
new_my_program:我还是个学生,但就我们学生的角度来看,像清华大学出版社你们这些人是没资格出书的。一个老师如果教育学生犯罪那就是个垃圾老师,你们出书的本来更是影响几代人,比一般的老师的影响力更大的多,你们的垃圾程度是可想而知的。以前看了《清华梦的破灭》这个文章后,我对心目中的清华园产生了严重的鄙视,现在再看了陈皓大哥的帖子,我更是鄙视你们。进清华的学生是何等的厉害,何等的意气风发。但是出清华的学生呢,好的就留……
文章分类
收藏
    相册
    我的BLOG
    耗子小筑(非技术)(RSS)
    陈皓专栏(技 术)(RSS)
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 跟我一起写 Makefile(一)收藏

    新一篇: 跟我一起写 Makefile(三) | 旧一篇: 跟我一起写 Makefile(十四)

    跟我一起写 Makefile


     陈皓

    概述
    ——

    什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。

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

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

    现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。

    在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。

     

    关于程序的编译和链接
    ——————————

    在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是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.

    好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。

     

    Makefile 介绍
    ———————

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

    首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
        1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
        2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
        3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

    只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。


    一、Makefile的规则

    在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。

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

        target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

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

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

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

    说到底,Makefile的东西就是这样一点,好像我的这篇文档也该结束了。呵呵。还不尽然,这是Makefile的主线和核心,但要写好一个Makefile还不够,我会以后面一点一点地结合我的工作经验给你慢慢到来。内容还多着呢。:)


    二、一个示例

    正如前面所说的,如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。

        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
        insert.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 main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

    反斜杠(\)是换行符的意思。这样比较便于Makefile的易读。我们可以把这个内容保存在文件为“Makefile”或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文件edit。如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“make clean”就可以了。

    在这个makefile中,目标文件(target)包含:执行文件edit和中间目标文件(*.o),依赖文件(prerequisites)就是冒号后面的那些 .c 文件和 .h文件。每一个 .o 文件都有一组依赖文件,而这些 .o 文件又是执行文件 edit 的依赖文件。依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。

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

    这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。

    下一页->

    (版权所有,转载时请注明作者和出处) 

     

    发表于 @ 2004年02月24日 16:48:00|评论(loading...)|编辑

    新一篇: 跟我一起写 Makefile(三) | 旧一篇: 跟我一起写 Makefile(十四)

    评论

    #rickyzhang 发表于2005-02-12 10:15:00  IP: 218.14.129.*
    写得不错,赞!
    # 发表于2005-06-20 13:47:00  IP: 61.186.252.*
    很好啊,我就是看不懂,自己要努力学习了.
    #chenmingshu 发表于2005-08-26 09:14:00  IP: 211.100.4.*
    对于像我这样的新手真是一根救命草啊,非常的感谢啊。不知以后有问题的话,可以请教么?如果可以的话方便告知怎么联系么?
    #thinkx 发表于2005-08-26 17:06:00  IP: 211.100.4.*
    写的非常好,文笔流畅,内容详实。
    #tony 发表于2006-03-16 16:03:00  IP: 218.229.194.*
    好文!!慢慢学习......
    #good 发表于2006-03-17 20:15:00  IP: 162.38.137.*
    希望能做一个可供打印的pdf版本出来
    #莹儿 发表于2006-05-23 16:56:00  IP: 218.4.93.*
    谢谢,请以后多写这样有用的东西,供大家学习。
    #古久先生 发表于2006-06-28 17:05:00  IP: 61.50.158.*
    好文章,
    现在的很多所谓教科书,浮躁的多,抄来抄去,象这种真正有用的问题,阐述比较好的,我发现的里面,作者是第一个,多谢了
    #碎花 发表于2006-06-30 16:43:00  IP: 218.249.181.*
    文章牛啊!中国要是多几个这样的强人,不久也会出个盖茨了!
    支持你!
    #林 发表于2006-07-12 15:05:00  IP: 202.103.100.*
    相当不错!!!终于知道在Linux 下编程从哪开始了。
    #make 发表于2006-10-14 14:31:00  IP: 10.193.154.*
    http://theory.uwinnipeg.ca/gnu/make/make_toc.html

    确实有许多例子是一样的
    #幼稚鬼 发表于2006-11-23 21:22:00  IP: 210.85.100.*
    寫得很棒,正愁不知道要問誰相關的問題
    #leehq 发表于2006-12-11 13:52:55  IP: 221.7.137.*
    好文啊,多谢多谢!
    #qinwenping 发表于2007-08-20 14:13:06  IP: 222.209.223.*
    谢谢,很全面!
    #wzbhbb 发表于2007-08-27 10:29:35  IP: 123.56.213.*
    好文章,十分感谢!!!
    #yongcaige 发表于2007-12-13 15:58:02  IP: 202.99.27.*
    前辈的文章内容简洁又实用,文笔也很好,看了真让我这个linux编程新手受益匪浅。
    谢谢您!!
    以您为榜样!!希望您能继续源源不断的写出这么优秀的文章!
    再次道谢!!
    #xuejian653 发表于2007-12-25 17:21:40  IP: 124.67.4.*
    真是一片好文章呀,看过之后让人茅塞顿开,就是下一页怎么点不开了?
    #psusong 发表于2008-04-21 00:21:33  IP: 58.240.35.*
    Thanks

    it is a good file

    I love it
    #fatcat 发表于2008-06-16 16:48:12  IP: 61.144.54.*
    关于那个自动推导的一节,有点错误。按照你的makefile,make了一次,然后如果修改一下display.c,再make的话,他会提示edit是最新的,就是说他检测不到display.c的修改了,这个错误可大可小
    #Scratch 发表于2008-08-30 21:39:13  IP: 125.33.186.*
    感谢陈老师。您让人真的很尊敬!!!
    #ablenavy 发表于2008-09-26 15:23:01  IP: 61.148.18.*
    一溜看下来,终于明白makefile的写法了,非常感谢分享,继续学习……
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 陈皓