黄天噎死了:怎样编写Makefile文件 - Moose W. Oler的日志 - 网易博客

来源:百度文库 编辑:九乡新闻网 时间:2024/05/09 15:35:40

怎样编写Makefile文件

Debian2009-03-19 15:48:50阅读408评论3  字号:大中小 订阅

引言:makefile入门读本,有些翻译拿不准的保留原文。原作者的行文结构可能不太好理解,待全部验证后会根据自己的使用经验调整内容的布局。
转载请注明出处。
==========================================================================
怎样编写Makefile文件

原作者 : anonymous
译者 : Moose W. Oler (原文部分修改)
参考 : Make and Makefiles by Reg Quinton
原文链接:http://www.hsrl.rutgers.edu/ug/make_help.html
==========================================================================
1. 介绍
在使用Debian GNU/Linux的过程中,我们会经常用到(有意或无意识的)make工具。
make是UNIX自带的,最初由AT&T贝尔实验室的S.I. Feldman在1975年完成。
不过现在也有GNU版本(public domain versions)和其他系统的版本(例如:Vax/VMS)。
相关工具有编译器(如cc,f77,lex,yacc等)和shell编程工具(awk,sed,cp,rm等)
在阅读本文之前,作为背景知识,你需要知道如何使用以上工具。

重要的辅助工具:
lint(源码错误检查工具)
ctags(可在源程序内定位函数)
mkdepand
它们的功能都很强大,很多优秀的程序员在使用它们。

重要的相关工具:
SCCS(Source Code Control System源代码控制系统)
RCS(Revision Control System软件修订控制系统,推荐使用)
使用它们的目的在于自动完成并且优化程序/文件的结构,也就是说要留下足够多的信息,以便在其他人阅读
源代码的时候能够较轻松的理解。

==========================================================================
2.Makefile的命名
make在运行的时候,默认的是先查找叫做Makefile配置文件,如果没找到再找叫做makefile的文件。尽量使用
Makefile这个名字(你不觉得ls的时候,Makefile要比makefile突出吗?)

You can get away without any Makefile (but shouldn't)!
make有它自己默认的"rules"(rules这个关键词很重要,所以不翻译)。

==========================================================================
3.Makefile组成部分

3.1 注释Comments
以井号(#)开始的文本部分,被视为注释。
注释可以从一行的任意点开始,直到行尾。
例如:
# $Id: slides,v 1.2 1992/02/14 21:00:58 reggers Exp $

3.2 宏Macros
make有一个简单的宏定义和替换系统。
在Makefile中,宏定义是一个等号对。
例如:
MACROS= -me
PSROFF= groff -Tps
DITROFF= groff -Tdvi
CFLAGS= -O -systype bsd43
系统中有很多默认的宏——你应该遵循已有的宏命名约定。
要查看现有的rules/macros,使用如下命令:
% make -p
注意:如果将环境变量作为宏,export到make里使用,它会覆盖原有的宏。

也可以在命令行中定义宏:
% make "CFLAGS= -O" "LDFLAGS=-s" printenv cc -O printenv.c -s -o printenv

3.3 目标Targets
当你make一个特定目标的时候(比如说make all), 如果没指定make的顺序话,将从makefile的第一个开始make:
paper.dvi: $(SRCS)
$(DITROFF) $(MACROS) $(SRCS) >paper.dvi
注意:第二行以TAB开始,而不是空格(虽然看起来一样)。

如果target依赖的文件发生了变化,target就会被执行。
上边例子中的依赖文件是由$(SRC)语句指定的部分。

3.4 行的格式Continuation of Lines
在macros或rules非常长的时候,可以分开多行写,每行结尾以“\”结束。

3.5 常用宏Conventional Macros
有很多默认的宏(使用“make -p”查看)。
Most are pretty obvious from the rules in which they are used:
AR = ar
GFLAGS =
GET = get
ASFLAGS =
MAS = mas
AS = as
FC = f77
CFLAGS =
CC = cc
LDFLAGS =
LD = ld
LFLAGS =
LEX = lex
YFLAGS =
YACC = yacc
LOADLIBS =
MAKE = make
MAKEARGS = 'SHELL=/bin/sh'
SHELL = /bin/sh
MAKEFLAGS = b

3.6 特殊宏Special Macros
在尝试写自己的makefile之前,还需要了解一些特殊的宏:
1. $@ —— 正在被made的文件名
2. $? —— 有改动的依赖文件的文件名
例如,这个rule:
printenv: printenv.c
$(CC) $(CFLAGS) $? $(LDFLAGS) -o $@
也可以这样写:
printenv: printenv.c
$(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@

还有两个特殊的宏,它们用在隐式rule中:
1. $< 引起此行为的相关文件名
2. $* 由target和依赖文件共用的前缀

3.7 Makefile目标规则Makefile Target Rules
一个目标规则的写法是:
target [target...] : [dependent ....]
[ command ...]
方括号中的是可选项目,省略号代表可以有多项
注意:在第二行开头有一个TAB,第一行是顶头写的。

语义相当的简单。
The semantics is pretty simple.
当你输入“make target”的时候,make就去寻找叫做target的rule。
如果规则的依赖文件发生了变化,make就会一个一个地执行第二行的command(发生在宏替换之后)。
如果有些依赖必须被made,则先made这些依赖,然后递归回去。

如果某个command返回失败值,整个make过程就会终止。
这就是为什么要使用这个rule:
clean:
-rm *.o *~ core paper
如果command行以“-”开头的话,Make会忽略命令行调用时返回的提示信息。
eg. who cares if there is no core file?

Make会回显执行的commands, 当宏替换后,make会回显当前的命令,以便让你知道目前的内容和进度。
有时候,你也许想关掉这个功能,那么这样作:
install:
@echo You must be root to install

3.8 示例Example Target Rules
例如,为了管理在RCS中的源文件,使用如下rule:
SRCS=x.c y.c z.c
$(SRCS):
co $@

管理SCCS中的源文件 (有时候你希望"get"一个源文件):
$(SRCS):
sccs get $@

为了更有普遍性一些,我们可以将rule修改一下:
SRCS=x.c y.c z.c
# GET= sccs get
GET= co
$(SRCS):
$(GET) $@

又如,下面的rule建立一个对象文件的库:
lib.a: x.o y.o z.o
ar rvu lib.a x.o y.o z.o
ranlib lib.a

另外,你也许会喜欢这样写:
OBJ=x.o y.o z.o
AR=ar

lib.a: $(OBJ)
$(AR) rvu $@ $(OBJ)
ranlib $@
因为AR是一个默认宏,所以你也可以省略第二行(但是不推荐这样做)

如果你习惯于使用宏,你就能只定义少量的有普遍性的rule,然后反复的调用它们。
例如,在其他的目录中构建一个库:
INC=../misc
OTHERS=../misc/lib.a

$(OTHERS):
cd $(INC); make lib.a
注意:下面这种写法是错误的(虽然看起来没问题)
INC=../misc
OTHERS=../misc/lib.a

$(OTHERS):
cd $(INC)
make lib.a
因为rule中的command是在各自独立的shell中执行。
这导致了一些有意思的结构,和那种超长行。

这个rule可以生成多个文件的tags文件:
SRCS=x.c y.c z.c
CTAGS=ctags -x >tags

tags: $(SRCS)
${CTAGS} $(SRCS)
在一个大的工程中,tag文件列出了所有的函数和它们的定义。
tags是一个很好的工具。

可以用lint查找可能的错误所在:
lint:
lint $(CFLAGS) $(SRCS)
lint是一个相当不错的查错工具,用它检查那些无意识犯下的小错误再好不过了——如拼写类错误,错误的
参数等等。

3.9 一些基本的规则Some Basic Make Rule
你的Makefile最好具有以下三个target:
all、install、clean
1. make all -- 将所有的文件进行编译以便进行本地调试。
2. make install -- 将文件安装到正确位置。避免破坏安装文件
3. make clean -- 清除文件。清楚所有可执行的、临时的和对象文件。

一些其他的目标也会经常用到,比如tags和lint。

3.10 完整Makefile的示例An Example Makefile for printenv
# make the printenv command
#
OWNER=bin
GROUP=bin
CTAGS= ctags -x >tags
CFLAGS= -O
LDFLAGS= -s
CC=cc
GET=co
SRCS=printenv.c
OBJS=printenv.o
SHAR=shar
MANDIR=/usr/man/manl/printenv.l
BINDIR=/usr/local/bin
DEPEND= makedepend $(CFLAGS)

all: printenv

# To get things out of the revision control system
$(SRCS):
$(GET) $@
# To make an object from source
$(CC) $(CFLAGS) -c $*.c
# To make an executable
printenv: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS)

# To install things in the right place
install: printenv printenv.man
$(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 755 printenv $(BINDIR)
$(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 644 printenv.man $(MANDIR)
# where are functions/procedures?
tags: $(SRCS)
$(CTAGS) $(SRCS)

# what have I done wrong?
lint: $(SRCS)
lint $(CFLAGS) $(SRCS)

# what are the source dependencies
depend: $(SRCS)
$(DEPEND) $(SRCS)

# to make a shar distribution
shar: clean
$(SHAR) README Makefile printenv.man $(SRCS) >shar

# clean out the dross
clean:
-rm printenv *~ *.o *.bak core tags shar

# DO NOT DELETE THIS LINE -- make depend depends on it.
printenv.o: /usr/include/stdio.h

3.11 隐式规则Makefile Implicit Rules
假设有如下rule:
Consider the rule we used for printenv
printenv: printenv.c
$(CC) $(CFLAGS) printenv.c $(LDFLAGS) -o printenv

可以更一般化些:
We generalized a bit to get
printenv: printenv.c
$(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@

上边的第二行是普遍适用的,当把.c文件编译为可执行的文件时,就可以用它,而不仅仅限于printenv.c
这个文件。像这样的情况,就可以使用隐式rule:
.c:
$(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@

这个隐式规则指明如何将.c文件编译成可执行文件——运行cc进行编译链接,然后命名之。
之所以称其为隐式的,因为这个rule没有确定的指出某一个文件,而是含糊的划定了一个大的范围。

另一个常见的隐式rule是将.c文件生成.o文件(OBJ):
.o.c:
$(CC) $(CFLAGS) -c $<

也可以这样:
.o.c:
$(CC) $(CFLAGS) -c $*.c

3.12 make依赖Make Dependencies
使用include在源代码中很常见。
比如:
% cat program.c
#include
#include "defs.h"
#include "glob.h"
etc....
main(argc,argv)
etc...

隐式rule仅包含了部分的源代码依赖(它只知道.o文件依赖于.c文件),却无法解决包含依赖。
常用的解决办法是,将详细的依赖关系单独写出来:
etc...
$(CC) $(CFLAGS) -c $*.c
etc...
program.o: program.c defs.h glob.h

一般来说,通过隐式rule和独立的依赖列表就可以很好的解决所有的依赖问题。

不过,还有其他的工具可以自动的替你生成依赖关系列表。
例如(trivial):
DEPEND= makedepend $(CFLAGS)
etc...
# what are the source dependencies

depend: $(SRCS)
$(DEPEND) $(SRCS)
etc....
# DO NOT DELETE THIS LINE -- ....
printenv.o: /usr/include/stdio.h

使用这些工具(mkdepend,mkmkf等)已经很常见了,它们也不是太难理解和使用。
其实这些工具只是shell脚本,通过运行cpp(或者cc -M等)来查找所有的依赖关系。
然后把依赖关系添加到Makefile的结尾。
(EOF)
怎样编写Makefile文件 - Moose W. Oler的日志 - 网易博客 Linux平台Makefile文件的编写基础篇 怎样编写选股公式 - 心林的世界的日志 - 网易博客 编写HTML代码 - 理睬的日志 - 网易博客 公式编写入门 - 徐老的日志 - 网易博客 怎样找回断电、死机前未储存的文件 - 分享生活的日志 - 网易博客 【引用】雕刻艺术欣赏(音画) - 鹞子的日志 - 网易博客w 泰顺游记 - shen.w.x的日志 - 网易博客 图纸会审w - 人淡如菊的日志 - 网易博客 天干地支与六十甲子 - w的日志 - 网易博客 系统的启动文件 - 骐源的日志 - 网易博客 揭开福利彩票3D的中奖概率 Cbb语言编写 - 阿浪的日志 - 网易博客 信息简报编写方法和注意事项1 - zhangmingjunsir的日志 - 网易博客 自己制作简便的---清理垃圾文件的批处理---文件 - 网易唬鸠人的日志 - 网易博客 古今中国作家作品集(W-Z) - 香儿的日志 - 网易博客 《百万书库中国现代文学》 [W-Z] - 香儿的日志 - 网易博客 【国学应用大师翟鸿燊经典语录】 - rxy1220的日志 - 网易博客w 手诊脏腑图 - 祥哥的日志 - 网易博客w 怎样将网易博客日志搬到QQ空间? - 敏儿的日志 - 网易博客 怎样改掉急躁的性格 - 上善若水的日志 - 网易博客 教你怎样抓图 - 理睬的日志 - 网易博客 怎样拍摄集体合影 - 憶 芓的日志 - 网易博客 怎样解决虚拟内存不足问题 - 至死不渝的日志 - 网易博客 女人.怎样才算美丽? - 依恋的日志 - 网易博客