简单的Makefile

        在阅读Linux源代码过程中发现如果要全面了解Linux的结构、理解Linux的编程总体设计及思想必须首先全部读通Linux源代码中各级的Makefile文件。GNU Make 使用手册(3.79)版原文,在此基础上翻译了该手册,以满足对Linux源代码有兴趣或者希望采用GCC编写程序但对缺乏GNU Make全面了解之人士的需要。本教程约定使用Ubuntu,gcc编译器。

        GNUMakeTcn中文翻译版教程:http://download.csdn.net/detail/ljheee/9790852

一、Make 概述

        Make 可自动决定一个大程序中哪些文件需要重新编译,并发布重新编译它们的命令。本版本GNU Make使用手册由Richard M. Stallman and RolandMcGrath编著,是从Paul D. Smith撰写的V3.76版本发展过来的。

        GNU Make符合IEEE Standard 1003.2-1992 (POSIX.2) 6.2章节的规定。

        因为C语言程序更具有代表性,所以我们的例子基于C语言程序,但Make并不是仅仅能够处理C语言程序,它可以处理那些编译器能够在Shell命令下运行的的各种语言的程序。事实上,GNUMake不仅仅限于程序,它可以适用于任何如果一些文件变化导致另外一些文件必须更新的任务。

        如果要使用Make,必须先写一个称为Makefile的文件,该文件描述程序中各个文件之间的相互关系,并且提供每一个文件的更新命令。在一个程序中,可执行程序文件的更新依靠OBJ文件(.o文件),而OBJ文件是由源文件编译得来的。

        一旦合适的Makefile文件存在,每次更改一些源文件,在shell命令下简单的键入:

        make

        就能执行所有的必要的重新编译任务。Make程序根据Makefile文件中的数据和每个文件更改的时间戳决定哪些文件需要更新。对于这些需要更新的文件,Make基于Makefile文件发布命令进行更新,进行更新的方式由提供的命令行参数控制。具体操作请看后续。

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

二、Makefile文件介绍

        Make程序需要一个所谓的Makefile文件来告诉它干什么。在大多数情况下,Makefile文件告诉Make怎样编译和连接成一个程序。

        本章我们将讨论一个简单的Makefile文件,该文件描述怎样将8个C源程序文件和3个头文件编译和连接成为一个文本编辑器。Makefile文件可以同时告诉Make怎样运行所需要的杂乱无章的命令(例如,清除操作时删除特定的文件)。如果要看更详细、复杂的Makefile文件例子,请参阅复杂的Makefile文件例子一章。

        当Make重新编译这个编辑器时,所有改动的C语言源文件必须重新编译。如果一个头文件改变,每一个包含该头文件的C语言源文件必须重新编译,这样才能保证生成的编辑器是所有源文件更新后的编辑器。每一个C语言源文件编译后产生一个对应的OBJ文件,如果一个源文件重新编译,所有的OBJ文件无论是刚刚编译得到的或原来编译得到的必须从新连接,形成一个新的可执行文件。

1、规则的格式

一个简单的Makefile文件包含一系列的“规则”,其样式如下:

目标(target)…: 依赖(prerequiries)…

<tab>命令(command)

        …

        …

        目标(target)通常是要产生的文件的名称,目标的例子是可执行文件或OBJ文件。目标也可是一个执行的动作名称,诸如‘clean’。

依赖是用来输入从而产生目标的文件,一个目标经常有几个依赖。

        命令是Make执行的动作,一个规则可以含有几个命令,每个命令占一行。注意:每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab。这是不小心容易出错的地方。

        通常,如果一个依赖发生变化,则需要规则调用命令对相应依赖和服务进行处理从而更新或创建目标。但是,指定命令更新目标的规则并不都需要依赖,例如,包含和目标‘clern’相联系的删除命令的规则就没有依赖。

        规则一般是用于解释怎样和何时重建特定文件的,这些特定文件是这个详尽规则的目标。Make需首先调用命令对依赖进行处理,进而才能创建或更新目标。当然,一个规则也可以是用于解释怎样和何时执行一个动作。

        一个Makefile文件可以包含规则以外的其它文本,但一个简单的Makefile文件仅仅需要包含规则。虽然真正的规则比这里展示的例子复杂,但格式却是完全一样。

2、一个简单的Makefile文件

        一个简单的Makefile文件,该文件描述了一个称为文本编辑器(edit)的可执行文件生成方法,该文件依靠8个OBJ文件(.o文件),它们又依靠8个C源程序文件和3个头文件。

        在这个例子中,所有的C语言源文件都包含‘defs.h’ 头文件,但仅仅定义编辑命令的源文件包含‘command.h’头文件,仅仅改变编辑器缓冲区的低层文件包含‘buffer.h’头文件。

edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o

       gcc -o edit main.o kbd.ocommand.o display.o insert.o search.o files.o utils.o

 

main.o : main.c defs.h

        gcc -c main.c

kbd.o : kbd.c defs.h command.h

        gcc -c kbd.c

command.o : command.c defs.h command.h

        gcc -c command.c

display.o : display.c defs.h buffer.h

        gcc -c display.c

insert.o : insert.c defs.h buffer.h

        gcc -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

        gcc -c files.c

utils.o : utils.c defs.h

        gcc -c utils.c

clean :

        rm edit main.o kbd.ocommand.o display.o

           insert.o search.o files.outils.o

        我们把每一个长行使用反斜杠-新行法分裂为两行或多行,实际上它们相当于一行,这样做的意图仅仅是为了阅读方便。

        使用Makefile文件创建可执行的称为‘edit’的文件,在Linux终端键入:make

        使用Makefile文件从目录中删除可执行文件和目标,键入:make clean

        在这个Makefile文件例子中,目标包括可执行文件‘edit’和OBJ文件‘main.o’及‘kdb.o’。可执行文件‘edit’命名可自定义,但需要和第二行gcc -o edit名一致。依赖是C语言源文件和C语言头文件如‘main.c’和‘def.h’等。事实上,每一个OBJ文件即是目标也是依赖。所以命令行包括‘cc -c main.c’和‘cc -c kbd.c’。

        当目标是一个文件时,如果它的任一个依赖发生变化,目标必须重新编译和连接。任何命令行的第一个字符必须是‘Tab’字符,这样可以把Makefile文件中的命令行与其它行分别开来。(一定要牢记:Make并不知道命令是如何工作的,它仅仅能向您提供保证目标的合适更新的命令。Make的全部工作是当目标需要更新时,按照您制定的具体规则执行命令。)

        目标‘clean’不是一个文件,仅仅是一个动作的名称。正常情况下,在规则中‘clean’这个动作并不执行,目标‘clean’也不需要任何依赖。一般情况下,除非特意告诉make执行‘clean’命令,否则‘clean’命令永远不会执行。注意这样的规则不需要任何依赖,它们存在的目的仅仅是执行一些特殊的命令。像这些不需要依赖仅仅表达动作的目标称为假想目标。详细内容参见假想目标;参阅命令错误可以了解rm或其它命令是怎样导致make忽略错误的。

3、make命令处理Makefile文件的过程

        缺省情况下,make开始于第一个目标(假想目标的名称前带‘.’)。这个目标称为缺省最终目标(即make最终更新的目标,具体内容请看指定最终目标的参数一节)。

在上节的简单例子中,缺省最终目标是更新可执行文件‘edit’,所以我们将该规则设为第一规则。这样,一旦你给出命令:

make

make就会读当前目录下的makefile文件,并开始处理第一条规则。在本例中,第一条规则是连接生成‘edit’,但在make全部完成本规则工作之前,必须先处理‘edit’所依靠的OBJ文件。这些OBJ文件按照各自的规则被处理更新,每个OBJ文件的更新规则是编译其源文件。重新编译根据其依靠的源文件或头文件是否比现存的OBJ文件更‘新’,或者OBJ文件是否存在来判断。

         其它规则的处理根据它们的目标是否和缺省最终目标的依赖相关联来判断。如果一些规则和缺省最终目标无任何关联则这些规则不会被执行,除非告诉Make强制执行(如输入执行make clean命令)。

        在OBJ文件重新编译之前,Make首先检查它的依赖C语言源文件和C语言头文件是否需要更新。如果这些C语言源文件和C语言头文件不是任何规则的目标,make将不会对它们做任何事情。Make也可以自动产生C语言源程序,这需要特定的规则,如可以根据Bison或Yacc产生C语言源程序。

        在OBJ文件重新编译(如果需要的话)之后,make决定是否重新连接生成edit可执行文件。如果edit可执行文件不存在或任何一个OBJ文件比存在的edit可执行文件‘新’(根据文件时间戳来判断),则make重新连接生成edit可执行文件。

        这样,如果我们修改了‘insert.c’文件,然后运行make,make将会编译‘insert.c’文件更新‘insert.o’文件,然后重新连接生成edit可执行文件。如果我们修改了‘command.h’文件,然后运行make,make将会重新编译‘kbd.o’和‘command.o’文件,然后重新连接生成edit可执行文件。

三、完整演示

用vim编辑以下程序,包括2个头文件、3个源文件。用Makefile定义依赖关系。多个文件不需要手动逐个编译,最后用make命令生成程序可运行文件。

1、程序源代码

程序清单:

//main.c
#include "function1.h"
#include "function2.h" 
int main(int argc, char **argv) {
  function1_print("hello");
  function2_print("world");
	return 0;
}

//function1.h 

void function1_print(char *str); 
//function1.c 
#include "function1.h"
#include <stdio.h>
void function1_print(char *str)
{
  printf("This is function1 print %s\n", str);
}
//function2.h

void function2_print(char *str); 
//function2.c 
#include "function2.h"
#include <stdio.h>
void function2_print(char *str)
{
  printf("This is function2 print %s\n", str);
}

2、Makefile文件

        Makefile文件,与程序源代码放在同一个目录;文件名必须是Makefile这8个字符,大小写自定。执行make命令处理Makefile文件时,会优先去找大写文件名的Makefile。本例自定义可执行文件名sampleX。

Makefile文件如下:
sampleX : main.o function1.o function2.o 
	gcc -o sampleX main.o function1.o function2.o 
main.o : main.c function1.h function2.h
	gcc -c main.c
function1.o : function1.h
	gcc -c function1.c
function2.o : function2.h
	gcc -c function2.c

3、用make命令处理Makefile文件

        打开Linux 终端,cd进入工程目录,键入make命令,自动编译生成可运行文件。结果例如下图:


 最后在终端键入: ./sampleX  即可运行。

完整工程免积分下载:http://download.csdn.net/detail/ljheee/9790898

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值