Chinaunix首页 | 论坛 | 博客
  • 博客访问: 477106
  • 博文数量: 122
  • 博客积分: 5000
  • 博客等级: 大校
  • 技术积分: 1540
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-26 11:11
文章分类

全部博文(122)

文章存档

2010年(1)

2009年(76)

2008年(45)

我的朋友

分类: LINUX

2009-02-25 19:36:53

GNU make是一个用来控制软件构建过程的自动工具,程序员通过定义构建规则来控制代码的创建
过程。这些规则通常定义在一个名为 Makefile的文件中。Makefile被用来告诉 make编译哪些文件、
怎样编译和何时编译。Makefile中的每条规则事实上都包含如下一些内容:
◆ 目标(target)是 make最终需要创建的对象;
◆ 依赖(dependency)通常是一个列表,指明编译目标时需要用到的其它文件;
◆ 命令(command)也是一个列表,指明从依赖文件创建出目标对象所需要执行的命令。

变量
为了简化 Makefile的编写,make引入了变量。变量实际上是为文本串在 Makefile中定义一个
便于记忆的名称。变量的定义和应用与 Linux的环境变量一样,变量名大写,变量一旦定义之后,就可以通过将变量名用圆括号包起来,并在前面加上“$”符号来进行引用。
变量一般都在 Makefile的头部定义。如果变量的值发生了改变,很显然只需在一个地方进行修改
就可以了,从而大大简化了 Makefile的维护。下面是将前面用到的 Makefile利用变量进行改写后的
结果:
OBJS = control.o ui.o main.o
CC = GCC
CFLAGS = -Wall
all : program
program : $(OBJS)
$(CC) $(OBJS) -o program
control.o : control.c
$(CC) $(CFLAGS) -c -o control.o control.c
ui.o : ui.c
$(CC) $(CFLAGS) -c -o ui.o ui.c
main.o : main.c
$(CC) $(CFLAGS) -c -o main.o main.c
clean :
rm -f program $(OBJS)

make将其使用的变量细分为两类:递归展开变量和简单展开变量递归展开变量在被引用时会逐层展开,即如果在展开式中包含了对其它变量的引用,则这些变量也会被展开,直到没有需要被展开的变
量为止。假设变量 TOPDIR和 SUBDIR的定义如下:
TOPDIR = /home/xiaowp
SUBDIR = $(TOPDIR)/project
此时变量 SUBDIR的值在解析时会被正确地展开为/home/xiaowp/project,但对于下面的定义:
TOPDIR = /home/xiaowp
SUBDIR = $(TOPDIR)/project
SUBDIR = $(SUBDIR)/src
很清楚,希望得到的结果是/home/xiaowp/project/src,但实际并非如此。SUBDIR在引用时
会被递归展开,从而陷入一个无限循环当中,make能够检测到这个问题并报告如下错误:
*** Recursive variable 'SUBDIR' references itself (eventually). Stop
为了避免这个问题,可以使用简单展开变量。与递归展开变量在引用时展开不同,简单展开变量是
在定义处展开的,并且只展开一次,从而消除了变量的嵌套引用。在定义时,其语法与递归展开变量有
细微的不同:
TOPDIR = /home/xiaowp
SUBDIR := $(TOPDIR)/project
SUBDIR += /src
SUBDIR在第一次定义时使用“:=”将其值设置为“/home/xiaowp/project”,而在第二次定义
时 则 使 用 “ +=” 在 已 有 的 基 础 上 添 加 “ /src” , 这 样 就 使 得  SUBDIR 的 最 终 值 变 为“/home/xiaowp/project/src”。
许多程序员在 Makefile中只使用简单展开变量,以避免可能出现的错误。

除了用户自定义变量之外,在 Makefile中还可以使用环境变量、自动变量和预定义变量。使用环
境变量的方法相对来讲比较简单,make在启动时会自动读取系统当前已经定义了的环境变量,并且会创
建与之具有相同名称和数值的变量。需要注意的是,如果用户在 Makefile中定义了相同名称的变量,
那么用户自定义变量将会覆盖同名的环境变量。

此外,make还提供了一些预定义变量和自动变量,但它们看起来都不如自定义变量那么直观。之所
以称为自动变量是因为 make会自动用特定的、熟知的值来替换它们,表 1给出了常用的部分自动变量。
利用 make的自动变量和预定义变量,可以简化前面给出的那个 Makefile文件:

OBJS = control.o ui.o main.o
CC = GCC
CFLAGS = -Wall
all : program
program : $(OBJS)
$(CC) $(OBJS) -o $@
control.o : control.c
$(CC) $(CFLAGS) -c -o $@ $<
ui.o : ui.c

$(CC) $(CFLAGS) -c -o $@ $<
main.o : main.c
$(CC) $(CFLAGS) -c -o $@ $<
clean :
$(RM) program $(OBJS)

伪目标
在 Makefile中,并不是所有的目标都对应于磁盘上的文件。有的目标存在只是为了形成一条规则,
从而完成特定的工作,并不生成新的目标文件,这样的目标称为伪目标。它并不是真正意义上的目标文
件,只是为了满足 Makefile的语法规则而存在的。

在已经给出的 Makefile文件中,最后一个目标 clean就是伪目标。它规定了 make应该执行的命
令。当 make处理到目标 clean时,会先查看其对应的依赖对象。由于 clean没有任何依赖对象,所以
make会认为该目标是最新的而不会执行任何操作。为了编译这个目标体,必须手工执行如下命令:
# make clean
作为惯例,clean目标一般用于删除最终生成的可执行文件和在编译过程中产生的所有目标文件。
问题是,如果恰巧有一个名为 clean的文件存在时该怎么办呢?此时因为在这个规则里没有任何依赖对
象,所以目标文件肯定是最新的,规则中的命令无论如何也不会被执行,即使用命令“make clean”也
无济于事。解决这一问题的方法是标明该规则中的目标是伪目标,并不对应于任何文件。这可以通
.PHONY目标实现。它告诉 make不检查规则的目标文件是否存在于磁盘上,也不查找任何隐含规则,
而直接假设指定的目标需要被更新就行了。在使用了.PHONY之后,前面的给出的 Makefile文件就将
变为如下的内容:
OBJS = control.o ui.o main.o
CC = GCC
CFLAGS = -Wall
all : program
program : $(OBJS)
$(CC) $(OBJS) -o $@
control.o : control.c
$(CC) $(CFLAGS) -c -o $@ $<
ui.o : ui.c
$(CC) $(CFLAGS) -c -o $@ $<
main.o : main.c
$(CC) $(CFLAGS) -c -o $@ $<
.PHONY : clean
clean :
$(RM) program $(OBJS)

其它规则
除了可以在 Makefile中明确指定规则(显示规则)之外,make还维护了一整套隐式规则。隐式规
则可以在用户没有完整地给出某些命令的时候,自动执行恰当的操作。隐式规则最大的好处是可以简化
Makefile的编写和维护,例如前面给出的 Makefile运用隐式规则后可以简化为如下内容:
OBJS = control.o ui.o main.o
program : $(OBJS)
$(CC) $(OBJS) -o $@
.PHONY : clean
clean :
$(RM) program $(OBJS)

默认目标 program依赖于 control.o、ui.o和 main.o三个目标文件,但 Makefile中并没有
给出怎样编译生成这些目标的规则。此时 make就会使用隐式规则,对每一个名为 foo.o的目标文件,
找到与之对应的源代码 foo.c,然后使用“gcc -c foo.c -o foo.o”命令来生成对应的目标文件。
除了系统预定义的隐式规则外,在 Makefile中还可以定义自己的隐式规则,这种规则也被称为模
式规则。模式规则类似于普通规则,但它的目标必须含有“%”这一通配符,以便能与任何非空字符相匹
配,与目标对应的依赖文件中也必须使用通配符,例如下面的规则:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

上面的规则将告诉 make所有形为 foo.o的目标文件,都应该根据指定的命令从源文件 foo.c编译
而来。

小结
在构建大型的软件项目时,make是一个优秀的持续集成工具。它对于软件开发过程来讲非常重要。
本文介绍了基本的 make命令,以及如何编写简单实用的 Makefile文件,相信用户已经能够使用 make
来管理软件项目的创建和维护过程了。

(摘自opensourse -- 200902期)
比较简单全面的make文章,多看几次就入门了。
阅读(759) | 评论(0) | 转发(0) |
0

上一篇:简单修复grub

下一篇:龙芯初编译 dev-3210

给主人留下些什么吧!~~