Makefile学习笔记

Makefile学习笔记

概述


什么是makefile?或许很多Windows程序员都不知道这个东西,因为那些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都成为了一种在工程方面的编译方法。

不同厂商的make各不相同,也有不同的语法,但是本质都是在文件依赖性上做文章,这里仅对GNU的make进行讲述,版本make3.80.该make是应用最为广泛的,也是用的最多的,而且还是最遵循与IEEE 1003.2-1992标准的(POSIX2)。

这篇文档中,以C/C++源码作为讲述基础,其中必然涉及一些关于C/C++编译的知识,相关内容可查阅相关编译器文档获得,这里默认为gcc和g++。

关于程序的编译和链接


一般来说,无论是C、C++,首先要把源文件编译成中间代码文件,Windows下.obj或Unix下.o,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫做链接(link)。

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

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

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

Makefile介绍


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

首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感性认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。

我们的规则是:

  1. 如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接;
  2. 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件;
  3. 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

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

一、Makefile的规则

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

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

prequisites是生成target所需要的文件。

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

这是一个文件的依赖关系,也就是说,target中的一个或多个目标文件依赖于prerequisites中的文件,其生成规则定义在command中。因此,prerequisites中如果有一个及以上的文件比target要新的话,command中定义的命令就会被执行。这就是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 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易读。

把这个内容保存在文件名为Makefilemakefile的文件中,然后在该目录下,直接输入命令make命令就可以生成执行文件edit。如果要删除执行文件和所有的中间目标文件,那么只要简单地执行一下make clean就可以了。

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

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

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

三、make是如何工作的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • 来自陈浩的一片老文,但绝对营养。 示例工程:3 个头文件*.h,和 8 个 C 文件*.c。 初 编译过程,源文件...
    周筱鲁阅读 4,690评论 0 17
  • 1. 概述 1.1 前言 之前在Linux下写C/C++都是直接输命令行,虽然有使用make的经历,但没有自己动手...
    kophy阅读 3,865评论 0 19
  • 本文章介绍了makefile跟kconfig文件,包括编译过程与makefile编码规则。 编译过程:我们在进行l...
    超低空阅读 17,429评论 0 5
  • makefile关系到整个工程的编译规则,一个工程中的源文件不计其数,按其类型、功能、模块分别放在若干的目录当中,...
    Joe_HUST阅读 1,876评论 0 3
  • 最近两天花时间读了一下陈皓老师的《跟我一起写Makefile》,这篇文章非常地详细地介绍了make的用法以及Mak...
    David栗子阅读 3,408评论 0 3