分享

make和makefile入门zz :: SkyBlue

 软件团队头目 2006-04-18

make和makefile入门
澳洲白面鸽 ----FREOS项目小组成员, 2003.5.10


本文讲述的是简单的make和makefile基础知识,帮助大家了解minix的boot目录下
的makefile文件,还要求大家先了解linux下的一些常见命令。

make的作者:Richard Stallman and Roland McGrath
GNU make满足POSIX.2的标准。
如果想执行make命令,首先编写一个makefile文件,该文件主要是描述你的
程序中所有文件的关系以及你所用的命令(编译命令等)。在一个程序中,可执行文
件是从目标文件升级(update)而来。如果你创建了一个合适的makefile文件,当你
改变了部分源文件内容时,你可通过执行make命令来重新编译。
make程序通过使用makefile作为配置文件,通过检测文件的更新时间,来决
定哪些文件需要重新编译。你也可以通过给make命令带命令行参数来决定那些文件
需要重新编译。一般,默认使用makefile文件来告诉make命令如何编译和链接程序。
makefile的常见语法规则:
1. target ... : dependencies ...
command
...
...
target一般为程序所生成的文件名。例如,是可执行文件名或目标文件名;一
个目标也可以是一个将要执行的动作的名称,见下例中的clean。
dependencies就是作为输入文件,被用来生成目标文件。一个目标文件可以由
好几个输入文件编译而成。
command就是make所执行的动作,可以由好几个命令组成,每个命令独占一行。
注意,每个命令行开头必须有一个Tab键,千万不要忘记。
通常,命令是用来编译输入文件以生成目标文件的。当然,命令也可以不需要
任何依赖(dependencies)。除了上述语法规则模块,一个makefile文件可能还包
含其他内容。

2.一个简单的makefile文件的分析:
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -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
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

解析,\为续行符。edit目标文件依赖main.o、kbd.o、command.o、 display.o、insert.o、search.o、files.o和utils.o等八个文件,并通
过随后的CC命令编译而成,其它类似。执行make命令即可生成edit可执行文件或
上述八个.o文件。执行make clean命令可删除edit可执行文件和上
述八个.o文件。
make命令并不在乎你使用什么编译命令(它由你来决定),它只在乎文
件之间的依赖关系,并重新编译需要更新的文件。目标clean并不是一个文
件,而是一个动作名,如果你不想使用clean,那么它和其他的规则模块没有任何
关系。
3.make如何处理makefile文件:
make一般从第一个规则块(rule)开始(以.开头的目标名不能算作一个
rule),被称作默认目标(default goal),也就是make命令要生成的最终
文件。如上例,edit是最终的目标文件,被作为第一个rule。当你发出make命令
后,make命令查找当前目录中的makefile文件,然后开始执行
第一个rule。如上例,第一个rule就是生成edit可执行文件。在完全执行
该rule之前,它先要处理该rule中所有的依赖(dependencies)。而这些依赖
(dependencies)又必须根据它们自己的rule来生成。如果一个目标文件的依
赖文件比它本身更新,或者目标文件根本就不存在,那么将根据对应的rule
重新编译生成新目标文件。除了第一个rule外,其它的rule也能执行,是因
为第一个rule的依赖(dependencies)与其他的rule有关,否则只有第一个
rule被执行;如果你想执行出第一个rule以外的其他独立rule,那么就必须
通过make命令行参数来指明,例如上面的make clean。

4.makefile文件中变量的使用:
例如,我们常常用objects, OBJECTS, objs, OBJS, obj, 或者OBJ, 来
表示目标文件,例如上例,我们可以用:
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
那么在makefile文件中,可用$(objects)代替上述八个.o文件。

5.让make命令自己推理:
make命令有一个隐含的规则,它能通过查找同名的.c文件和cc -c命令来
自动更新.o文件。也就是在一个rule中,能自动把.c文件添加到依赖
(dependencies)列表中。这样上述例子可简写为:
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
-rm edit $(objects)
6.makefile的另一种风格:
把目标文件放在一起而不是把依赖放在一起,上例可修改为:
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)

$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
但是有人也不喜欢它,因为它不能一次看清某个目标文件的依赖情况。

7.删除目录或文件的rule:
.PHONY : clean
clean :
-rm edit $(objects)
其中,.PHONY : clean 可阻止make命令使用一个名为clean的真实文件,具体见
以后分析。

8.怎样编写一个makefile文件:
makefile包含五个方面:explicit rules(显式rule), implicit rules(隐式
rule), variable definitions(变量), directives(指示符), 和comments(注释)
。显式rule,指明目标文件的依赖以及创建或更新目标文件所用的命令;隐式
rule通过同名文件和指定命令来创建和更新目标文件;变量的定义见上面的例子
;指示符是为了帮助make命令在读取makefile文件时作一些特定的事情(见以后分
析);注释行一般用#开头。

9.命名一个makefile文件:
默认情况下,make命令会寻找下列文件:GNUmakefile, makefile和Makefile
。如果你不指定makefile文件,那么你必须指定一个最终的目标文件,make命令
会自动使用内部隐含的rule来编译。如果你不想用默认的makefile文件名,你也
可以通过 -f filename 或 --file=filename,来告诉make应该读取的文件。如果
你用 -f或 --file指定了多个文件,那么它们将按顺序被联接在一起。如果你用
-f或 --file指定,那么将不自动查找默认的makefile等文件。

10.包含其他的makefile文件:
include标识符告在诉make命令,在读makefile文件之前,要先读若干个其他
的makefile文件。include标识符使用方法为:include filenames...。在每行开
头的空格被忽略。但是不能以tab健开头,否则可能会被当作一个命令行。在
include和filename之间必须要用空格隔开。当make处理一个include标识符时,
它先暂缓处理当前的makefile,转而读该标识符所列举的文件。当这些文件被处
理完毕后,make接着读被悬挂的makefile文件。
11.假冒的目标(phony target):
一个假冒目标不是一个真正的文件名,它仅仅表示某些特定make命令的扩展
,用假冒的目标文件有两个原因:避免和同名文件发生冲突。例如:
clean:
rm *.o temp
因为rm命令不能创建一个clean文件,可能永远都没有那样的文件存在。因此,每
当你执行make clean命令时,rm命令都会被执行。但是如果有一个clean文件存在
了,那么这个假冒的目标将不会工作。因为它没有依赖,所以所存在的clean文件
被认为是最新的,而导致rm命令不能被执行。为了避免这个问题,可以显式申明
该目标是phony类型,即:
.PHONY: clean
clean:
rm *.o temp
申明以后,就可以知道clean并非一个真正的文件,在每次执行make clean时,它
都必须被执行。当然,Phony targets也可以有依赖。当一个目录包含几个程序时
,在一个makefile文件中描述所有这些程序也很方便。用all假冒目标来表示,例
如:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
现在只需要用make命令就可以重新编译这三个文件,也可用参数来指定编译特定
的文件,例如make prog1 prog3。
12.主要定义变量:
$* 不包含扩展名的目标文件名称。
$+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的
依赖文件。
$< 第一个依赖文件的名称。
$? 所有依赖文件,以空格分开,这些依赖文件的修改日期比目标文件的创
建日期晚。
$@ 目标的完整名称。
$^ 所有的依赖文件,以空格分开,不包含重复的依赖文件。
$% 如果目标是归档成员,则该变量表示目标的归档成员名。

13.用户的标准目标:
所有的GNU程序都应该有些列目标(部分略):
all: 编译全部程序。它应该是缺省的目标。
install: 编译全部程序,并把可执行文件,库文件等文件拷贝到它应该在的
目录。
clean: 删除文件。

欢迎访问FREOS项目主页
*********************minix的boot目录下makefile解析*******************
# Makefile for the boot monitor package. 注释
#
CC= exec cc 命令
CC86= exec cc -mi86 -Was-ncc

CFLAGS= -I.. -m -O
LD= $(CC) -s -.o
LD86= $(CC86) -.o
BIN= /usr/bin
MDEC= /usr/mdec

all: bootblock boot masterboot extboot installboot edparams 目标文件

installboot.o bootimage.o: image.h
boot.o bootimage.o: boot.h
rawfs.o rawfs86.o installboot.o boot.o bootimage.o: rawfs.h 申明依赖关系

bootblock: bootblock.s
$(LD86) bootblock.s -o bootblock

masterboot: masterboot.s
$(LD86) masterboot.s -o masterboot

extboot: extboot.s
$(LD86) extboot.s -o extboot

boot.o: boot.c
$(CC86) $(CFLAGS) -c boot.c

bootimage.o: bootimage.c
$(CC86) $(CFLAGS) -c bootimage.c

rawfs86.o: rawfs.c rawfs.o
ln -f rawfs.c rawfs86.c
$(CC86) $(CFLAGS) -c rawfs86.c
rm rawfs86.c
-cmp -s rawfs.o rawfs86.o && ln -f rawfs.o rawfs86.o

boot: boothead.s boot.o bootimage.o rawfs86.o
$(LD86) boothead.s -i boot.o bootimage.o rawfs86.o -o boot
install -S 12kb boot

installboot: installboot.o rawfs.o
$(CC) $(STRIP) -i -o installboot installboot.o rawfs.o
install -S 6kw installboot

edparams: edparams.c
$(CC) $(CFLAGS) $(STRIP) -i -o edparams edparams.c
install -S 16kw edparams

install: $(MDEC)/bootblock $(MDEC)/boot $(MDEC)/masterboot \
$(MDEC)/extboot $(BIN)/installboot $(BIN)/edparams
执行make install命令才执行?

$(MDEC)/bootblock: bootblock
install -cs -o bin -m 644 $? $@

$(MDEC)/boot: boot
install -cs -o bin -m 644 $? $@

$(MDEC)/masterboot: masterboot
install -cs -o bin -m 644 $? $@

$(MDEC)/extboot: extboot
install -cs -o bin -m 644 $? $@

$(BIN)/installboot: installboot
install -cs -o bin $? $@

$(BIN)/edparams: edparams
install -cs -o bin $? $@

clean:
rm -f *.bak *.o
rm -f bootblock installboot boot masterboot extboot edparams

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多