Make
程序最初设计是为了维护
C
程序文件防止不必要的重新编译。在使用命令行编译器的时候,修改了一个工程中的头文件,如何确保包含这个头文件的所有文件都得到编译?版本的生成是使用批处理程序,编译那些文件依赖于程序的维护者,在模块之间相互引用头文件的情况下,要将所有需要重新编译的文件找出来是一件痛苦的事情;在找到这些文件之后,修改批处理进行编译。实际上这些工作可以让
make
程序来自动完成,
make
工具对于维护一些具有相互依赖关系的文件特别有用,它对文件和命令的联系(在文件改变时调用来更新其它文件的程序)提供一套编码方法。
Make
工具的基本概念类似于
Proglog
语言,你告诉
make
需要做什么,提供一些规则,
make
来完成剩下的工作。
简介
make
工作自动确定工程的哪部分需要重新编译,执行命令去编译它们。虽然
make
多用于
C
程序,然而只要提供命令行的编译器,就可以将其用于任何语言。实际上,
make
工具的应用范围不仅于编程,它可以用来描述任何一些文件改变需要自动更新另一些文件的任务来使用它。
准备工作
如果要使用
make
,必须写一个叫做
“makefile”
的文件,这个文件描述工程中文件之间的关系,提供更新每个文件的命令。典型的工程是这样的:可执行文件靠目标文件来更新,目标文件靠编译源文件来更新。
Makefile
写好之后,每次更改了源文件后,只要执行
make
就足够了,所有必要的重新编译将执行。
Make
程序利用
makefile
中的数据库和文件的最后修改时间来确定那个文件需要更新;对于需要更新的文件,
make
执行数据库中记录的命令。
可以提供命令行参数给
make
来控制那个文件需要重新编译。
Makefile
介绍
Makefile
文件告诉
make
做什么,多数情况是怎样编译和链接一个程序。
这里有一个简单的
makefile
,描述如何编译链接由
8
个
C
文件和
3
个头文件组成的一个编辑器:
edit : main.o kbd.o command.o display.o / insert.o serach.o files.o utils.occ –o edit main.o kbd.o command.o display.o / insert.o search.o files.o utils.omain.o : main.c defs.hcc –c main.ckdb.o : kbd.c defs.h command.hcc –c kbd.ccommand.o : command.c defs.h command.hcc -c command.cdisplay.o : display.c defs.h buffer.hcc -c display.cinsert.o : insert.c defs.h buffer.hcc -c insert.csearch.o : search.c defs.h buffer.hcc -c search.cfiles.o : files.c defs.h buffer.h command.hcc -c files.cutils.o : utils.c defs.hcc -c utils.cclean :rm edit main.o kbd.o command.o display.o / insert.o search.o files.o utils.o
将长行用
/
分开便于阅读,这和使用一个长行的作用是一样的。使用这个
makefile
创建可执行文件
“edit”
时运行
make
就可以了;如果要将可执行文件和目标文件删除,执行
make cleanmake
重新编译这个编辑器时,每个更改的
C
文件必须重新编译;如果头文件更改了,每个包含头文件的
C
文件必须重新编译;每次编译产生一个对应于原文件的目标文件。最终,目标文件链接在一起产生新的可执行文件。
规则简介
makefile
中的规则是这样的:
TARGET … : DEPENDENCIES …COMMAND…
目标(
TARGET
)程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如
“clean”
。
依赖(
DEPENDENCIES
)是用来产生目标的输入文件,一个目标通常依赖于多个文件。
命令(
COMMAND
)是
make
执行的动作,一个可以有多个命令,每个占一行。注意:每个命令行的起始字符必须为
TAB
字符!
有依赖关系规则中的命令通常在依赖文件变化时负责产生
target
文件,
make
执行这些命令更新或产生
target
。规则可以没有依赖关系,如包含
target “clean”
的规则。
规则解释如何和何时重做该规则中的文件,
make
根据依赖关系执行产生或更新目标;规则也说明如何和何时执行动作。有的规则看起来很复杂,但都符合上述模式。
make
工作原理
缺省
make
从第一个
target
开始(第一个非
’.’
开始的
target
),这称作缺省目标。在上述的
makefile
中,缺省目标是更新执行程序
’edit’
,将这个目标置于最前面。当执行
make
的时候,
make
程序从当前目录读入
makefile
开始处理第一个规则;在例子中,这个规则是重新链接
’edit’
;在
make
处理这个规则之前,必须处理
’edit’
所依赖的那些文件的规则,例子中是目标文件。这些文件按照他们自己的规则处理:通过编译源文件来更新每个
’.o’
文件;当依赖关系中的源文件或头文件比目标文件新,或目标文件不存在时,必须重新编译。
其它的规则被处理是因为他们的
target
是目标的依赖,和目标没有依赖关系的规则不会被处理,除非指定
make
处理(如
make clean
)。
在重新编译目标文件之前,
make
会试图更新它的依赖:源文件和头文件。例子中的
makefile
对源文件和头文件未指定任何操作:
’.c’
和
’.h’
文件不是任何规则的目标。确认所有的目标文件都是最新的之后,
make
决定是否重新链接
’edit’
:如果
’edit’
不存在,或者任何一个目标文件都比它新,则链接工作将进行。
这样,如果改变
insert.c
运行
make
,
make
会编译这个文件来更新
’insert.o’
,然后链接
’edit’
;如果修改了
’command.h’
运行
make
,
’kbd.o’
,
’command.o’
,
’files.o’
会重新生成,链接
’edit’
。
使用变量
在例子中,在规则
’edit’
中,目标文件被列出来两次:
edit : main.o kbd.o command.o display.o / insert.o search.o files.o utils.occ -o edit main.o kbd.o command.o display.o / insert.o search.o files.o utils.o
这样的重复容易出错:假设工程中加入了一个新的目标文件,可能只将其加入了一个列表中;通过使用变量可以消除这种风险:变量允许一个预定义的字符串在多个地方被替换。
在
makefile
中,可以写这样一行来定义
’object’
变量:
objects = main.o kbd.o command.o display.o / insert.o search.o files.o utils.o
于是在需要目标文件名列表的地方,使用
$(object)
来代替变量的值。以下是使用了变量以后的
makefile
:
objects = main.o kbd.o command.o display.o / insert.o search.o files.o utils.oedit : $(objects)cc -o edit $(objects)main.o : main.c defs.hcc -c main.ckbd.o : kbd.c defs.h command.hcc -c kbd.ccommand.o : command.c defs.h command.hcc -c command.cdisplay.o : display.c defs.h buffer.hcc -c display.cinsert.o : insert.c defs.h buffer.hcc -c insert.csearch.o : search.c defs.h buffer.hcc -c search.cfiles.o : files.c defs.h buffer.h command.hcc -c files.cutils.o : utils.c defs.hcc -c utils.cclean :rm edit $(objects)
简化命令
为每个文件写出编译命令不是必要的,因为
make
可以自己来做;以
’.c’
文件更新
’.o’
文件有一个隐含的规则,使用
’cc -c’
命令。
Make
将利用
’cc –c main.c –o main.o’
来将
main.c
编译为
main.o
,因此在生成目标文件的规则中,可以省略命令。
当
’.c’
文件以这样的方式使用时,将自动加入到依赖关系中;由是在省略命令的前提下,可以将
’.c’
文件从依赖关系中省略。以下是简化过的
makefile
:
objects = main.o kbd.o command.o display.o / insert.o search.o files.o utils.oedit : $(objects) cc -o edit $(objects)main.o : defs.hkbd.o : defs.h command.hcommand.o : defs.h command.hdisplay.o : defs.h buffer.hinsert.o : defs.h buffer.hsearch.o : defs.h buffer.hfiles.o : defs.h buffer.h command.hutils.o : defs.h.PHONY : cleanclean : -rm edit $(objects)
另一种风格
如果
makefile
中的目标都是以隐含规则生成,可以将规则按照依赖关系分组:
objects = main.o kbd.o command.o display.o / insert.o search.o files.o utils.oedit : $(objects) cc -o edit $(objects)$(objects) : defs.hkbd.o command.o files.o : command.hdisplay.o insert.o search.o files.o : buffer.h
这里
’defs.h’
作为所有目标文件的依赖。这种风格是好是坏取决于个人喜好,它非常紧凑,但是将每个目标的依赖信息放在一起看起来更清楚一些。
清理
编写规则不至于编译程序。
Makefile
通常描述如何做其它事情:比如删除目录中的目标文件和可执行文件来清理目录。例子中是这样写的:
clean: rm edit $(objects)
实际情况是,我们需要处理一些意外事件:存在一个叫做
’clean’
的文件;如果
rm
出错,并不希望
make
过程停止下来,修改过的版本如下:
.PHONY : cleanclean : -rm edit $(objects)
这样的规则当然不能放在
makefile
的开始,因为这并不是我们缺省要做的工作。由于
’clean’
并不是
’edit’
的依赖,在运行
make
时没有参数时,这条规则不会执行;要执行这个规则,必须运行
’make clean’
。
转载请注明原文地址: https://ibbs.8miu.com/read-21794.html