无
论
是在
Linux
还
是在
Unix
环
境中,
make
都是一个非常重要的
编译
命令。不管是自己
进
行
项
目
开发还
是安装
应
用
软
件,我
们
都
经
常要用到
make
或
make install
。利用
make
工具,我
们
可以将大型的
开发项
目分解成
为
多个更易于管理的模
块
,
对
于一个包括几百个源文件的
应
用程序,使用
make
和
makefile
工具就可以
简洁
明快地理
顺
各个源文件之
间纷
繁
复杂
的相互
关
系。而且如此多的源文件,如果
每
次都要
键
入
gcc
命令
进
行
编译
的
话
,那
对
程序
员
来
说简
直就是一
场
灾
难
。而
make
工具
则
可自
动
完成
编译
工作,并且可以只
对
程序
员
在上次
编译
后修改
过
的部分
进
行
编译
。因此,有效的利用
make
和
makefile
工具可以大大提高
项
目
开发
的效率。同
时
掌握
make
和
makefile
之后,您也不会再面
对
着
Linux
下的
应
用
软
件手足无措了。
但令人 遗 憾的是,在 许 多 讲 述 Linux 应 用的 书 籍上都没有 详细 介 绍这 个功能 强 大但又非常 复杂 的 编译 工具。在 这 里我就向大家 详细 介 绍 一下 make 及其描述文件 makefile 。
Makefile 文件
Make 工具最主要也是最基本的功能就是通 过 makefile 文件来描述源程序之 间 的相互 关 系并自 动维护编译 工作。而 makefile 文件需要按照某 种语 法 进 行 编 写,文件中需要 说 明如何 编译 各个源文件并 连 接生成可 执 行文件,并要求定 义 源文件之 间 的依 赖关 系。 makefile 文件是 许 多 编译 器 -- 包括 Windows NT 下的 编译 器 -- 维护编译 信息的常用方法,只是在集成 开发环 境中,用 户 通 过 友好的界面修改 makefile 文件而已。
在 UNIX 系 统 中, 习惯 使用 Makefile 作 为 makfile 文件。如果要使用其他文件作 为 makefile , 则 可利用 类 似下面的 make 命令 选项 指定 makefile 文件:
$ make -f Makefile.debug
例如,一个名 为 prog 的程序由三个 C 源文件 filea.c 、 fileb.c 和 filec.c 以及 库 文件 LS 编译 生成, 这 三个文件 还 分 别 包含自己的 头 文件 a.h 、 b.h 和 c.h 。通常情况下, C 编译 器将会 输 出三个目 标 文件 filea.o 、 fileb.o 和 filec.o 。假 设 filea.c 和 fileb.c 都要声明用到一个名 为 defs 的文件,但 filec.c 不用。即在 filea.c 和 fileb.c 里都有 这样 的声明:
#include "defs"
那 么 下面的文档就描述了 这 些文件之 间 的相互 联 系 :
---------------------------------------------------------
#It is a example for describing makefile
prog : filea.o fileb.o filec.o
cc filea.o fileb.o filec.o -LS -o prog
filea.o : filea.c a.h defs
cc -c filea.c
fileb.o : fileb.c b.h defs
cc -c fileb.c
filec.o : filec.c c.h
cc -c filec.c
----------------------------------------------------------
这 个描述文档就是一个 简单 的 makefile 文件。
从上面的例子注意到,第一个字符 为 # 的行 为 注 释 行。第一个非注 释 行指定 prog 由三个目 标 文件 filea.o 、 fileb.o 和 filec.o 链 接生成。第三行描述了如何从 prog 所依 赖 的文件建立可 执 行文件。接下来的 4 、 6 、 8 行分 别 指定三个目 标 文件,以及它 们 所依 赖 的 .c 和 .h 文件以及 defs 文件。而 5 、 7 、 9 行 则 指定了如何从目 标 所依 赖 的文件建立目 标 。
当 filea.c 或 a.h 文件在 编译 之后又被修改, 则 make 工具可自 动 重新 编译 filea.o ,如果在前后两次 编译 之 间 , filea.C 和 a.h 均没有被修改,而且 test.o 还 存在的 话 ,就没有必要重新 编译 。 这种 依 赖关 系在多源文件的程序 编译 中尤其重要。通 过这种 依 赖关 系的定 义 , make 工具可避免 许 多不必要的 编译 工作。当然,利用 Shell 脚本也可以达到自 动编译 的效果,但是, Shell 脚本将全部 编译 任何源文件,包括哪些不必要重新 编译 的源文件,而 make 工具 则 可根据目 标 上一次 编译 的 时间 和目 标 所依 赖 的源文件的更新 时间 而自 动 判断 应 当 编译 哪个源文件。
Makefile 文件作 为 一 种 描述文档一般需要包含以下内容 :
◆ 宏定 义
◆ 源文件之 间 的相互依 赖关 系
◆ 可 执 行的命令
Makefile 中允 许 使用 简单 的宏指代源文件及其相 关编译 信息,在 Linux 中也称宏 为变 量。在引用宏 时 只需在 变 量前加 $ 符号,但 值 得注意的是,如果 变 量名的 长 度超 过 一个字符,在引用 时 就必 须 加 圆 括号()。
下面都是有效的宏引用:
$(CFLAGS)
$2
$Z
$(Z)
其中最后两个引用是完全一致的。
需要注意的是一些宏的 预 定 义变 量,在 Unix 系 统 中, $* 、 $@ 、 $? 和 $< 四个特殊宏的 值 在 执 行命令的 过 程中会 发 生相 应 的 变 化,而在 GNU make 中 则 定 义 了更多的 预 定 义变 量。 关 于 预 定 义变 量的 详细 内容,宏定 义 的使用可以使我 们 脱离那些冗 长 乏味的 编译选项 , 为编 写 makefile 文件 带 来很大的方便。
---------------------------------------------------------
# Define a macro for the object files
OBJECTS= filea.o fileb.o filec.o
# Define a macro for the library file
LIBES= -LS
# use macros rewrite makefile
prog: $(OBJECTS)
cc $(OBJECTS) $(LIBES) -o prog
……
---------------------------------------------------------
此 时 如果 执 行不 带 参数的 make 命令,将 连 接三个目 标 文件和 库 文件 LS ;但是如果在 make 命令后 带 有新的宏定 义 :
make "LIBES= -LL -LS"
则 命令行后面的宏定 义 将覆盖 makefile 文件中的宏定 义 。若 LL 也是 库 文件,此 时 make 命令将 连 接三个目 标 文件以及两个 库 文件 LS 和 LL 。
在 Unix 系 统 中没有 对 常量 NULL 作出明确的定 义 ,因此我 们 要定 义 NULL 字符串 时 要使用下述宏定 义 :
STRINGNAME=
Make 命令
在 make 命令后不 仅 可以出 现 宏定 义 , 还 可以跟其他命令行参数, 这 些参数 指定了需要 编译 的目 标 文件。其 标 准形式 为 :
target1 [target2 …]:[:][dependent1 …][;commands][#…]
[(tab) commands][#…]
方括号中 间 的部分表示可 选项 。 Targets 和 dependents 当中可以包含字符、数字、句点和 "/" 符号。除了引用, commands 中不能含有 "#", 也不允 许换 行。
在通常的情况下命令行参数中只含有一个 ":" ,此 时 command 序列通常和 makefile 文件中某些定 义 文件 间 依 赖关 系的描述行有 关 。如果 与目 标 相 关连 的那些描述行指定了相 关 的 command 序列,那 么 就 执 行 这 些相 关 的 command 命令,即使在分号和 (tab) 后面的 aommand 字段甚至有可能是 NULL 。如果那些与目 标 相 关连 的行没有指定 command ,那 么 将 调 用系 统 默 认 的目 标 文件生成 规则 。
如果命令行参数中含有两个冒号 "::" , 则 此 时 的 command 序列也 许 会和 makefile 中所有描述文件依 赖关 系的行有 关 。此 时 将 执 行那些与目 标 相 关连 的描述行所指向的相 关 命令。同 时还 将 执 行 build-in 规则 。
如果在 执 行 command 命令 时 返回了一个 非 "0" 的出 错 信号,例如 makefile 文件中出 现 了 错误 的目 标 文件名或者出 现 了以 连 字符打 头 的命令字符串, make 操作一般会就此 终 止,但如果 make 后 带 有 "-i" 参数, 则 make 将忽略此 类 出 错 信号。
Make 命本身可 带 有四 种 参数: 标 志、宏定 义 、描述文件名和目 标 文件名。其 标 准形式 为 :
Make [flags] [macro definitions] [targets]
Unix 系 统 下 标 志位 flags 选项 及其含 义为 :
-f file 指定 file 文件 为 描述文件,如果 file 参数 为 "-" 符,那 么 描述文件指向 标 准 输 入。如果没有 "-f" 参数, 则 系 统 将默 认 当前目 录 下名 为 makefile 或者名 为 Makefile 的文件 为 描述文件。在 Linux 中, GNU make 工具在当前工作目 录 中按照 GNUmakefile 、 makefile 、 Makefile 的 顺 序搜索 makefile 文件。
-i 忽略命令 执 行返回的出 错 信息。
-s 沉默模式,在 执 行之前不 输 出相 应 的命令行信息。
-r 禁止使用 build-in 规则 。
-n 非 执 行模式, 输 出所有 执 行命令,但并不 执 行。
-t 更新目 标 文件。
-q make 操作将根据目 标 文件是否已 经 更新返回 "0" 或非 "0" 的状 态 信息。
-p 输 出所有宏定 义 和目 标 文件描述。
-d Debug 模式, 输 出有 关 文件和 检测时间 的 详细 信息。
Linux 下 make 标 志位的常用 选项 与 Unix 系 统 中稍有不同,下面我 们 只列出了不同部分:
-c dir 在 读 取 makefile 之前改 变 到指定的目 录 dir 。
-I dir 当包含其他 makefile 文件 时 ,利用 该选项 指定搜索目 录 。
-h help 文 挡 , 显 示所有的 make 选项 。
-w 在 处 理 makefile 之前和之后,都 显 示工作目 录 。
通 过 命令行参数中的 target ,可指定 make 要 编译 的目 标 ,并且允 许 同 时 定 义编译 多个目 标 ,操作 时 按照从左向右的 顺 序依次 编译 target 选项 中指定的目 标 文件。如果命令行中没有指定目 标 , 则 系 统 默 认 target 指向描述文件中第一个目 标 文件。
通常, makefile 中 还 定 义 有 clean 目 标 ,可用来清除 编译过 程中的中 间 文件,例如:
clean:
rm -f *.o
运行 make clean 时 ,将 执 行 rm -f *.o 命令,最 终删 除所有 编译过 程中 产 生的所有中 间 文件。
隐 含 规则
在 make 工具中包含有一些内置的或 隐 含的 规则 , 这 些 规则 定 义 了如何从不同的依 赖 文件建立特定 类 型的目 标 。 Unix 系 统 通常支持一 种 基于文件 扩 展名即文件名后 缀 的 隐 含 规则 。 这种 后 缀规则 定 义 了如何将一个具有特定文件名后 缀 的文件(例如 .c 文件), 转换 成 为 具有另一 种 文件名后 缀 的文件(例如 .o 文件):
.c:.o
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
系 统 中默 认 的常用文件 扩 展名及其含 义为 :
.o 目 标 文件
.c C 源文件
.f FORTRAN 源文件
.s 汇编 源文件
.y Yacc-C 源 语 法
.l Lex 源 语 法
在早期的 Unix 系 统 系 统 中 还 支持 Yacc-C 源 语 法和 Lex 源 语 法。在 编译过 程中,系 统 会首先在 makefile 文件中 寻 找与目 标 文件相 关 的 .C 文件,如果 还 有与之相依 赖 的 .y 和 .l 文件, 则 首先将其 转换为 .c 文件后再 编译 生成相 应 的 .o 文件;如果没有与目 标 相 关 的 .c 文件而只有相 关 的 .y 文件, 则 系 统 将直接 编译 .y 文件。
而 GNU make 除了支持后 缀规则 外 还 支持另一 种类 型的 隐 含 规则 -- 模式 规则 。 这种规则 更加通用,因 为 可以利用模式 规则 定 义 更加 复杂 的依 赖 性 规则 。模式 规则 看起来非常 类 似于正 则规则 ,但在目 标 名称的前面多了一个 % 号,同 时 可用来定 义 目 标 和依 赖 文件之 间 的 关 系,例如下面的模式 规则 定 义 了如何将任意一个 file.c 文件 转换为 file.o 文件:
%.c:%.o
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
#EXAMPLE#
下面将 给 出一个 较为 全面的示例来 对 makefile 文件和 make 命令的 执 行 进 行 进 一 步 的 说 明,其中 make 命令不 仅涉 及到了 C 源文件 还 包括了 Yacc 语 法。本例 选 自 "Unix Programmer's Manual 7th Edition, Volume 2A" Page 283-284
下面是描述文件的具体内容:
---------------------------------------------------------
#Description file for the Make command
#Send to print
P=und -3 | opr -r2
#The source files that are needed by object files
FILES= Makefile version.c defs main.c donamc.c misc.c file.c /
dosys.c gram.y lex.c gcos.c
#The definitions of object files
OBJECTS= vesion.o main.o donamc.o misc.o file.o dosys.o gram.o
LIBES= -LS
LINT= lnit -p
CFLAGS= -O
make: $(OBJECTS)
cc $(CFLAGS) $(OBJECTS) $(LIBES) -o make
size make
$(OBJECTS): defs
gram.o: lex.c
cleanup:
-rm *.o gram.c
install:
@size make /usr/bin/make
cp make /usr/bin/make ; rm make
#print recently changed files
print: $(FILES)
pr $? | $P
touch print
test:
make -dp | grep -v TIME>1zap
/usr/bin/make -dp | grep -v TIME>2zap
diff 1zap 2zap
rm 1zap 2zap
lint: dosys.c donamc.c file.c main.c misc.c version.c gram.c
$(LINT) dosys.c donamc.c file.c main.c misc.c version.c /
gram.c
rm gram.c
arch:
ar uv /sys/source/s2/make.a $(FILES)
----------------------------------------------------------
通常在描述文件中 应 象上面一 样 定 义 要求 输 出将要 执 行的命令。在 执 行了 make 命令之后, 输 出 结 果 为 :
$ make
cc -c version.c
cc -c main.c
cc -c donamc.c
cc -c misc.c
cc -c file.c
cc -c dosys.c
yacc gram.y
mv y.tab.c gram.c
cc -c gram.c
cc version.o main.o donamc.o misc.o file.o dosys.o gram.o /
-LS -o make
13188+3348+3044=19580b=046174b
最后的数字信息是
执
行
"@size make"
命令的
输
出
结
果。之所以只有
输
出
结
果而没有相
应
的命令行,是因
为
"@size make"
命令以
"@"
起始,
这
个符号禁止打印
输
出它所在的命令行。
但令人 遗 憾的是,在 许 多 讲 述 Linux 应 用的 书 籍上都没有 详细 介 绍这 个功能 强 大但又非常 复杂 的 编译 工具。在 这 里我就向大家 详细 介 绍 一下 make 及其描述文件 makefile 。
Makefile 文件
Make 工具最主要也是最基本的功能就是通 过 makefile 文件来描述源程序之 间 的相互 关 系并自 动维护编译 工作。而 makefile 文件需要按照某 种语 法 进 行 编 写,文件中需要 说 明如何 编译 各个源文件并 连 接生成可 执 行文件,并要求定 义 源文件之 间 的依 赖关 系。 makefile 文件是 许 多 编译 器 -- 包括 Windows NT 下的 编译 器 -- 维护编译 信息的常用方法,只是在集成 开发环 境中,用 户 通 过 友好的界面修改 makefile 文件而已。
在 UNIX 系 统 中, 习惯 使用 Makefile 作 为 makfile 文件。如果要使用其他文件作 为 makefile , 则 可利用 类 似下面的 make 命令 选项 指定 makefile 文件:
$ make -f Makefile.debug
例如,一个名 为 prog 的程序由三个 C 源文件 filea.c 、 fileb.c 和 filec.c 以及 库 文件 LS 编译 生成, 这 三个文件 还 分 别 包含自己的 头 文件 a.h 、 b.h 和 c.h 。通常情况下, C 编译 器将会 输 出三个目 标 文件 filea.o 、 fileb.o 和 filec.o 。假 设 filea.c 和 fileb.c 都要声明用到一个名 为 defs 的文件,但 filec.c 不用。即在 filea.c 和 fileb.c 里都有 这样 的声明:
#include "defs"
那 么 下面的文档就描述了 这 些文件之 间 的相互 联 系 :
---------------------------------------------------------
#It is a example for describing makefile
prog : filea.o fileb.o filec.o
cc filea.o fileb.o filec.o -LS -o prog
filea.o : filea.c a.h defs
cc -c filea.c
fileb.o : fileb.c b.h defs
cc -c fileb.c
filec.o : filec.c c.h
cc -c filec.c
----------------------------------------------------------
这 个描述文档就是一个 简单 的 makefile 文件。
从上面的例子注意到,第一个字符 为 # 的行 为 注 释 行。第一个非注 释 行指定 prog 由三个目 标 文件 filea.o 、 fileb.o 和 filec.o 链 接生成。第三行描述了如何从 prog 所依 赖 的文件建立可 执 行文件。接下来的 4 、 6 、 8 行分 别 指定三个目 标 文件,以及它 们 所依 赖 的 .c 和 .h 文件以及 defs 文件。而 5 、 7 、 9 行 则 指定了如何从目 标 所依 赖 的文件建立目 标 。
当 filea.c 或 a.h 文件在 编译 之后又被修改, 则 make 工具可自 动 重新 编译 filea.o ,如果在前后两次 编译 之 间 , filea.C 和 a.h 均没有被修改,而且 test.o 还 存在的 话 ,就没有必要重新 编译 。 这种 依 赖关 系在多源文件的程序 编译 中尤其重要。通 过这种 依 赖关 系的定 义 , make 工具可避免 许 多不必要的 编译 工作。当然,利用 Shell 脚本也可以达到自 动编译 的效果,但是, Shell 脚本将全部 编译 任何源文件,包括哪些不必要重新 编译 的源文件,而 make 工具 则 可根据目 标 上一次 编译 的 时间 和目 标 所依 赖 的源文件的更新 时间 而自 动 判断 应 当 编译 哪个源文件。
Makefile 文件作 为 一 种 描述文档一般需要包含以下内容 :
◆ 宏定 义
◆ 源文件之 间 的相互依 赖关 系
◆ 可 执 行的命令
Makefile 中允 许 使用 简单 的宏指代源文件及其相 关编译 信息,在 Linux 中也称宏 为变 量。在引用宏 时 只需在 变 量前加 $ 符号,但 值 得注意的是,如果 变 量名的 长 度超 过 一个字符,在引用 时 就必 须 加 圆 括号()。
下面都是有效的宏引用:
$(CFLAGS)
$2
$Z
$(Z)
其中最后两个引用是完全一致的。
需要注意的是一些宏的 预 定 义变 量,在 Unix 系 统 中, $* 、 $@ 、 $? 和 $< 四个特殊宏的 值 在 执 行命令的 过 程中会 发 生相 应 的 变 化,而在 GNU make 中 则 定 义 了更多的 预 定 义变 量。 关 于 预 定 义变 量的 详细 内容,宏定 义 的使用可以使我 们 脱离那些冗 长 乏味的 编译选项 , 为编 写 makefile 文件 带 来很大的方便。
---------------------------------------------------------
# Define a macro for the object files
OBJECTS= filea.o fileb.o filec.o
# Define a macro for the library file
LIBES= -LS
# use macros rewrite makefile
prog: $(OBJECTS)
cc $(OBJECTS) $(LIBES) -o prog
……
---------------------------------------------------------
此 时 如果 执 行不 带 参数的 make 命令,将 连 接三个目 标 文件和 库 文件 LS ;但是如果在 make 命令后 带 有新的宏定 义 :
make "LIBES= -LL -LS"
则 命令行后面的宏定 义 将覆盖 makefile 文件中的宏定 义 。若 LL 也是 库 文件,此 时 make 命令将 连 接三个目 标 文件以及两个 库 文件 LS 和 LL 。
在 Unix 系 统 中没有 对 常量 NULL 作出明确的定 义 ,因此我 们 要定 义 NULL 字符串 时 要使用下述宏定 义 :
STRINGNAME=
Make 命令
在 make 命令后不 仅 可以出 现 宏定 义 , 还 可以跟其他命令行参数, 这 些参数 指定了需要 编译 的目 标 文件。其 标 准形式 为 :
target1 [target2 …]:[:][dependent1 …][;commands][#…]
[(tab) commands][#…]
方括号中 间 的部分表示可 选项 。 Targets 和 dependents 当中可以包含字符、数字、句点和 "/" 符号。除了引用, commands 中不能含有 "#", 也不允 许换 行。
在通常的情况下命令行参数中只含有一个 ":" ,此 时 command 序列通常和 makefile 文件中某些定 义 文件 间 依 赖关 系的描述行有 关 。如果 与目 标 相 关连 的那些描述行指定了相 关 的 command 序列,那 么 就 执 行 这 些相 关 的 command 命令,即使在分号和 (tab) 后面的 aommand 字段甚至有可能是 NULL 。如果那些与目 标 相 关连 的行没有指定 command ,那 么 将 调 用系 统 默 认 的目 标 文件生成 规则 。
如果命令行参数中含有两个冒号 "::" , 则 此 时 的 command 序列也 许 会和 makefile 中所有描述文件依 赖关 系的行有 关 。此 时 将 执 行那些与目 标 相 关连 的描述行所指向的相 关 命令。同 时还 将 执 行 build-in 规则 。
如果在 执 行 command 命令 时 返回了一个 非 "0" 的出 错 信号,例如 makefile 文件中出 现 了 错误 的目 标 文件名或者出 现 了以 连 字符打 头 的命令字符串, make 操作一般会就此 终 止,但如果 make 后 带 有 "-i" 参数, 则 make 将忽略此 类 出 错 信号。
Make 命本身可 带 有四 种 参数: 标 志、宏定 义 、描述文件名和目 标 文件名。其 标 准形式 为 :
Make [flags] [macro definitions] [targets]
Unix 系 统 下 标 志位 flags 选项 及其含 义为 :
-f file 指定 file 文件 为 描述文件,如果 file 参数 为 "-" 符,那 么 描述文件指向 标 准 输 入。如果没有 "-f" 参数, 则 系 统 将默 认 当前目 录 下名 为 makefile 或者名 为 Makefile 的文件 为 描述文件。在 Linux 中, GNU make 工具在当前工作目 录 中按照 GNUmakefile 、 makefile 、 Makefile 的 顺 序搜索 makefile 文件。
-i 忽略命令 执 行返回的出 错 信息。
-s 沉默模式,在 执 行之前不 输 出相 应 的命令行信息。
-r 禁止使用 build-in 规则 。
-n 非 执 行模式, 输 出所有 执 行命令,但并不 执 行。
-t 更新目 标 文件。
-q make 操作将根据目 标 文件是否已 经 更新返回 "0" 或非 "0" 的状 态 信息。
-p 输 出所有宏定 义 和目 标 文件描述。
-d Debug 模式, 输 出有 关 文件和 检测时间 的 详细 信息。
Linux 下 make 标 志位的常用 选项 与 Unix 系 统 中稍有不同,下面我 们 只列出了不同部分:
-c dir 在 读 取 makefile 之前改 变 到指定的目 录 dir 。
-I dir 当包含其他 makefile 文件 时 ,利用 该选项 指定搜索目 录 。
-h help 文 挡 , 显 示所有的 make 选项 。
-w 在 处 理 makefile 之前和之后,都 显 示工作目 录 。
通 过 命令行参数中的 target ,可指定 make 要 编译 的目 标 ,并且允 许 同 时 定 义编译 多个目 标 ,操作 时 按照从左向右的 顺 序依次 编译 target 选项 中指定的目 标 文件。如果命令行中没有指定目 标 , 则 系 统 默 认 target 指向描述文件中第一个目 标 文件。
通常, makefile 中 还 定 义 有 clean 目 标 ,可用来清除 编译过 程中的中 间 文件,例如:
clean:
rm -f *.o
运行 make clean 时 ,将 执 行 rm -f *.o 命令,最 终删 除所有 编译过 程中 产 生的所有中 间 文件。
隐 含 规则
在 make 工具中包含有一些内置的或 隐 含的 规则 , 这 些 规则 定 义 了如何从不同的依 赖 文件建立特定 类 型的目 标 。 Unix 系 统 通常支持一 种 基于文件 扩 展名即文件名后 缀 的 隐 含 规则 。 这种 后 缀规则 定 义 了如何将一个具有特定文件名后 缀 的文件(例如 .c 文件), 转换 成 为 具有另一 种 文件名后 缀 的文件(例如 .o 文件):
.c:.o
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
系 统 中默 认 的常用文件 扩 展名及其含 义为 :
.o 目 标 文件
.c C 源文件
.f FORTRAN 源文件
.s 汇编 源文件
.y Yacc-C 源 语 法
.l Lex 源 语 法
在早期的 Unix 系 统 系 统 中 还 支持 Yacc-C 源 语 法和 Lex 源 语 法。在 编译过 程中,系 统 会首先在 makefile 文件中 寻 找与目 标 文件相 关 的 .C 文件,如果 还 有与之相依 赖 的 .y 和 .l 文件, 则 首先将其 转换为 .c 文件后再 编译 生成相 应 的 .o 文件;如果没有与目 标 相 关 的 .c 文件而只有相 关 的 .y 文件, 则 系 统 将直接 编译 .y 文件。
而 GNU make 除了支持后 缀规则 外 还 支持另一 种类 型的 隐 含 规则 -- 模式 规则 。 这种规则 更加通用,因 为 可以利用模式 规则 定 义 更加 复杂 的依 赖 性 规则 。模式 规则 看起来非常 类 似于正 则规则 ,但在目 标 名称的前面多了一个 % 号,同 时 可用来定 义 目 标 和依 赖 文件之 间 的 关 系,例如下面的模式 规则 定 义 了如何将任意一个 file.c 文件 转换为 file.o 文件:
%.c:%.o
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
#EXAMPLE#
下面将 给 出一个 较为 全面的示例来 对 makefile 文件和 make 命令的 执 行 进 行 进 一 步 的 说 明,其中 make 命令不 仅涉 及到了 C 源文件 还 包括了 Yacc 语 法。本例 选 自 "Unix Programmer's Manual 7th Edition, Volume 2A" Page 283-284
下面是描述文件的具体内容:
---------------------------------------------------------
#Description file for the Make command
#Send to print
P=und -3 | opr -r2
#The source files that are needed by object files
FILES= Makefile version.c defs main.c donamc.c misc.c file.c /
dosys.c gram.y lex.c gcos.c
#The definitions of object files
OBJECTS= vesion.o main.o donamc.o misc.o file.o dosys.o gram.o
LIBES= -LS
LINT= lnit -p
CFLAGS= -O
make: $(OBJECTS)
cc $(CFLAGS) $(OBJECTS) $(LIBES) -o make
size make
$(OBJECTS): defs
gram.o: lex.c
cleanup:
-rm *.o gram.c
install:
@size make /usr/bin/make
cp make /usr/bin/make ; rm make
#print recently changed files
print: $(FILES)
pr $? | $P
touch print
test:
make -dp | grep -v TIME>1zap
/usr/bin/make -dp | grep -v TIME>2zap
diff 1zap 2zap
rm 1zap 2zap
lint: dosys.c donamc.c file.c main.c misc.c version.c gram.c
$(LINT) dosys.c donamc.c file.c main.c misc.c version.c /
gram.c
rm gram.c
arch:
ar uv /sys/source/s2/make.a $(FILES)
----------------------------------------------------------
通常在描述文件中 应 象上面一 样 定 义 要求 输 出将要 执 行的命令。在 执 行了 make 命令之后, 输 出 结 果 为 :
$ make
cc -c version.c
cc -c main.c
cc -c donamc.c
cc -c misc.c
cc -c file.c
cc -c dosys.c
yacc gram.y
mv y.tab.c gram.c
cc -c gram.c
cc version.o main.o donamc.o misc.o file.o dosys.o gram.o /
-LS -o make
13188+3348+3044=19580b=046174b
描述文件中的最后几条命令行在 维护编译 信息方面非常有用。其中 "print" 命令行的作用是打印 输 出在 执 行 过 上次 "make print" 命令后所有改 动过 的文件名称。系 统 使用一个名 为 print 的 0 字 节 文件来确定 执 行 print 命令的具体 时间 ,而宏 $? 则 指向那些在 print 文件改 动过 之后 进 行修改的文件的文件名。如果想要指定 执 行 print 命令后,将 输 出 结 果送入某个指定的文件,那 么 就可修改 P 的宏定 义 :
make print "P= cat>zap"
在 Linux 中大多数 软 件提供的是源代 码 ,而不是 现 成的可 执 行文件, 这 就要求用 户 根据自己系 统 的 实际 情况和自身的需要来配置、 编译 源程序后, 软 件才能使用。只有掌握了 make 工具,才能 让 我 们 真正享受到到 Linux 这 个自由 软 件世界的 带给 我 们 无 穷乐 趣。