Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1140368
  • 博文数量: 322
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 3276
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-17 09:21
文章分类

全部博文(322)

文章存档

2010年(155)

2009年(167)

我的朋友

分类: 嵌入式

2010-04-30 23:53:42

make是Linux下的一款程序自动维护工具,配合makefile的使用,就能够根据程序中模块的修改情况,自动判断应该对那些模块重新编译,从而保证软件是由最新的模块构成。
 
 
1. 使用make的原因

当我们在开发的程序中涉及众多源文件时,常常会引起一些问题。首先,如果程序只有两三个源文件,那么修改代码后直接重新编译全部源文件就行了,但是如果程序的源文件较多,这种简单的处理方式就有问题了。

设想一下,如果我们只修改了一个源文件,却要重新编译所有源文件,那么这显然是在浪费时间。其次,要是只重新编译那些受影响的文件的话,我们又该如何确定这些文件呢?比如我们使用了多个头文件,那么它们会被包含在各个源文件中,修改了某些头文件后,那些源文件受影响,哪些与此无关呢?如果采取拉网式大检查的话,可就费劲了。

由此可以看出,源文件多了可真是件让人头疼的事。幸运的是,实用程序make可以帮我们解决这两个问题——当程序的源文件改变后,它能保证所有受影响的文件都将重新编译,而不受影响的文件则不予编译。

 

2. Make程序的命令行选项和参数

make程序能够根据程序中各模块的修改情况,自动判断应对哪些模块重新编译,保证软件是由最新的模块构建的。至于检查哪些模块,以及如何构建软件由makefile文件来决定

虽然make可以在makefile中进行配置,除此之外我们还可以利用make程序的命令行选项对它进行即时配置。Make命令参数的典型序列如下所示:

make [-f makefile文件名][选项][宏定义][目标] 

–k:
如果使用该选项,即使make程序遇到错误也会继续向下运行;如果没有该选项,在遇到第一个错误时make程序马上就会停止,那么后面的错误情况就不得而知了。我们可以利用这个选项来查出所有有编译问题的源文件。

–n:
该选项使make程序进入非执行模式,也就是说将原来应该执行的命令输出,而不是执行。

–f
指定作为makefile的文件的名称。 如果不用该选项,那么make程序首先在当前目录查找名为makefile的文件,如果没有找到,它就会转而查找名为Makefile的文件。如果您在Linux下使用GNU Make的话,它会首先查找GNUmakefile,之后再搜索makefile和Makefile。按照惯例,许多Linux程序员使用Makefile,因为这样能使Makefile出现在目录中所有以小写字母命名的文件的前面。所以,最好不要使用GNUmakefile这一名称,因为它只适用于make程序的GNU版本。

当我们想构建指定目标的时候,比如要生成某个可执行文件,那么就可以在make命令行中给出该目标的名称;如果命令行中没有给出目标的话,make命令会设法构建makefile中的第一个目标。我们可以利用这一特点,将all作为makefile中的第一个目标,然后将让目标作为all所依赖的目标,这样,当命令行中没有给出目标时,也能确保它会被构建。

 
3. Makefile文件
 
事实上,只有make命令还是不够的,还必用须makefile告诉它要做什么以及怎么做才行,对于程序开发而言,就是告诉make命令应用程序的组织情况。

一般情况下,makefile会跟项目的源文件放在同一个目录中。另外,系统中可以有多个makefile,一般说来一个项目使用一个makefile就可以了;如果项目很大的话,我们就可以考虑将它分成较小的部分,然后用不同的makefile来管理项目的不同部分。

make命令和Makefile配合使用,能给我们的项目管理带来极大的便利,除了用于管理源代码的编译之外,还用于建立手册页,同时还能将应用程序安装到指定的目录。

因为Makefile用于描述系统中模块之间的相互依赖关系,以及产生目标文件所要执行的命令,所以,一个makefile由依赖关系和规则两部分内容组成。下面分别加以解释。

依赖关系由一个目标和一组该目标所依赖的源文件组成。这里所说的目标就是将要创建或更新的文件,最常见的是可执行文件。规则用来说明怎样使用所依赖得文件来建立目标文件。

当make命令运行时,会读取makefile来确定要建立的目标文件或其他文件,然后对源文件的日期和时间进行比较,从而决定使用那些规则来创建目标文件。一般情况下,在建立起最终的目标文件之前,肯定免不了要建立一些中间性质的目标文件。这时,Make命令也是使用makefile来确定这些目标文件的创建顺序,以及用于它们的规则序列。

 

4. Makefile中的依赖关系

make程序自动生成和维护通常是可执行模块或应用程序的目标,目标的状态取决于它所依赖的那些模块的状态。Make的思想是为每一块模块都设置一个时间标记,然后根据时间标记和依赖关系来决定哪一些文件需要更新。一旦依赖模块的状态改变了,make就会根据时间标记的新旧执行预先定义的一组命令来生成新的目标。

依赖关系规定了最终得到的应用程序跟生成它的各个源文件之间的关系。

在makefile中,我们可以用目标名称,加冒号,后跟空格加上用于生产目标模块的文件来描述模块之间的依赖关系,多文件时使用空格来分割。

例如:

  

图1  模块间的依赖关系

main: main.o f1.o f2.o
main.o: main.c def1.h
f1.o: f1.c def1.h def2.h
f2.o: f2.c def2.h def3.h

 

默认时,make程序只更新makefile中的第一个目标,如果希望更新多个目标文件的话,可以使用一个特殊的目标all,假如我们想在一个makefile中更新main和hello这两个程序文件的话,可以加入下列语句达到这个目的:

all: main hello

 

5. Makefile中的规则

除了指明目标和模块之间的依赖关系之外,makefile还要规定相应的规则来描述如何生成目标,或者说使用哪些命令来根据依赖模块产生目标。

makefile是以相关行为基本单位的,相关行用来描述目标、模块及规则(即命令行)三者之间的关系。一个相关行格式通常为:冒号左边是目标(模块)名;冒号右边是目标所依赖的模块名;紧跟着的规则(即命令行)是由依赖模块产生目标所使用的命令。相关行的格式为:

目标:[依赖模块][;命令]

习惯上写成多行形式,如下所示:

目标:[依赖模块]

命令

命令
 

 

需要注意的是,如果相关行写成一行,“命令”之前用分号“;”隔开,如果分成多行书写的话,后续的行务必以tab字符为先导。对于makefile而言,空格字符和tab字符是不同的。所有规则所在的行必须以tab键开头,而不是空格键。

此外,如果在makefile文件中的行尾加上空格键的话,也会导致make命令运行失败。

make能够正确的判断出这些文件的处理顺序,并按相应的顺序调用规则部分规定的相应命令来创建这些文件。当这些命令执行时,make程序会按照执行情况来显示这些命令。

 

6. Makefile中的宏

在makefile中的宏可以代表一些文件名或选项。宏的作用类似于C语言中的define,利用它们来代表某些多处使用而又可能发生变化的内容,可以节省重复修改的工作,还可以避免遗漏。

Make的宏分为两类,一类是用户自己定义的宏,一类是系统内部定义的宏。用户定义的宏必须在makefile或命令行中明确定义,系统定义的宏不由用户定义。

例如:

all: main
# 使用的编译器
CC = gcc
#包含文件所在目录
INCLUDE = .
# 在开发过程中使用的选项
CFLAGS = -g -Wall –ansi
# 在发行时使用的选项
# CFLAGS = -O -Wall –ansi
main: main.o f1.o f2.o
$(CC) -o main main.o f1.o f2.o
main.o: main.c def1.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
f1.o: f1.c def1.h def2.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c f1.c
f2.o: f2.c def2.h def3.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c f2.c

在makefile中定义宏的基本语法是:

宏标识符=值列表

宏标识符即宏的名称通常全部大写,关于值列表,既可以是零项,也可以是一项或者多项。当一个宏定义之后,我们就可以通过$(宏标识符)或者${宏标识符}来访问这个标识符所代表的值了。

常用的内部宏有:

$? :比目标的修改时间更晚的那些依赖模块表。
$@ :当前目标的全路径名。可用于用户定义的目标名的相关行中。
$< :比给定的目标文件时间标记更新的依赖文件名。
$* :去掉后缀的当前目标名。例如,若当前目标是pro.o,则$*表示pro。
 

阅读(856) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~