概述
make
1.make概述
make工具用来自动判断一个大型程序的哪些部分需要重新编译以及实用哪些命令来编译。本文档介绍由Richard Stallman和Roland McGrath开发的GNU make,GNU make从v3.76开始由Paul D.Smith负责。GNU make符合IEEE1003.2-1992标准(POSIX.2标准)6.2条款。由于C语言的通用性,本文档以C语言为例介绍make,然而,你可以对任何支持命令行的语言编译器使用make。事实上,make不仅仅限于程序。你可以使用它来描述任何目标文件依赖于其他文件自动更新的任务。
准备
准备、运行make
为了使用make,你必须写一个描述你程序中使用文件依赖关系和更新每个文件的命令的makefile文件。对程序而言,典型地,可执行文件依赖于目标文件,目标文件通过编译源文件获得。当有一个合适的makefile文件时,在你每次更新一些源文件时,shell命令make用来执行所有必须得重编译。make使用makefile和文件的最终修改时间来确定哪些文件需要更新。对于每一个需要更新的文件,make出发makefile中对应的记录。当然,你可以提供命令行参数来控制make如何重编译文件。
2.makefile介绍
你需要一个名为makefile的文件来告诉make做什么。通常,makefile记录如何编译和链接程序。我们以如何编译、链接一个文本编辑器为例来说明如何写makefile。在这个简单的例子中,有8个源文件和3个头文件。makefile也可以告诉make工具如何运行显示提供的命令,比如删除某些文件等。当make重新编译时,每个更改过的源文件都需要重编译。如果头文件变化了,每个包含该头文件的源文件都需要重编译。每一个编译都产生一个对应的目标文件。最终,如果有任何源文件被重新编译了,不管是新添加的还是之前编译过的,都必须链接起来生成新的可执行文件。
2.1规则介绍
一个最简单的makefile包含如下形式的规则:
target … : prerequisites …
recipe
…
…
target通常是程序生成的文件名,比如可执行文件和目标文件,也可以是要执行的命令,比如clean等。prerequisites是用来产生输出的输入文件。recipe可能包含多个命令,一行一个命令或者一行多个命令,在每个命令前面你需要一个tab。如果你tab之外的其他前缀,你可以设置.RECIPEPREFIX变量来改变。一般而言,recipe有一定的前置条件并包含在一个规则之中,旨在当前置条件改变时创建target。然而,也可以没有前置条件,比如包含删除命令规则的clean就没有前置条件。规则表示何时、怎样标记目标规则的文件。make在prerequisites前置条件的基础上执行recipe来创建或者更新target。同样,rule也可以解释何时、怎样执行命令。除了rule外,makefile可能包含其他内容,然而一个最简单的makefile可以只包含rule。rule可能比这里介绍的要复杂得多,但是这里介绍的模式或多或少地适用。
2.1一个简单的makefile
下面是一个直观的描述了一个可执行文件edit依赖于8个目标文件,8个目标文件依赖于8个源文件和3个头文件的makefile。在这个例子中,所有的c文件都包含defs.h,只有定义编辑命令的源文件包含commang.h,只有改变编辑器缓冲区的低级文件包含buffer.h。
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
我们用反斜杠或者换行来分割一个长的行,这就像使用一个长的行,但是更易读。为了适用这个makefile文件来生成名为edit的可执行文件,输入make即可。为了删除可执行文件和目标文件,输入make clean即可。在这个makefile文件中,target包括可执行文件edit,目标文件main.o和kdb.o。前置条件包括main.c和defs.h等。事实上,每一个.o文件既是一个target也是一个prerequisite。recipe包括cc -c main.c和cc -c kdb.c。
当target是一个文件时,如果前置条件有所改变,那么它需要被重新编译或者链接。在这个makefile中,edit依赖于每个目标文件,目标文件main.o依赖于源文件main.c和头文件defs.h。recipe可以在一行包含target和prerequisites。这些recipe表示怎样更新target文件。tab必须出现在recipe每行的头部来区别recipe和makefile文件中的其他内容。make对recipe的工作方式一无所知,其做的只是执行你指定的recipe。目标clean不是文件,仅仅是一个动作。正常情况下你不想执行这条动作,clean不是任何规则的前置条件。自然,除非你明确要clean,否则clean不会做任何事。clean不仅不是任何rule的前置条件,也不需要任何前置条件,clean的目的仅仅是执行某些recipe。仅仅执行命令的target称为phony target(伪目标)。
2.3make如何运行makefile
缺省情况下,make从第一个target开始(不是以.开始的target),这称为缺省目标。目标是make最终更新的target。你可以通过命令行参数或者.DEFAULT_GOAL变量改变这一目标。在上一部分提到的makefile中,缺省目标是更新可执行文件edit,因此我们把这条规则放在最前面。因此,当你输入命令make时,make读入当前目录的makefile文件,然后开始处理第一条规则。在这一例子中,rule是重新连接edit。在make可以顺利进行此rule之前,它必须进行edit依赖的规则,即目标文件。这些rule指示通过编译源文件来更新.o文件。当目标文件不存在或者前置条件如源文件和头文件较目标文件更新时,必须进行重编译。进行其他规则是因为他们的target是目标的前置条件。如果目标goal不依赖于某些rule,这些rule不会进行,除非明确指定make要进行,比如make clean。
在重编译目标文件之前,make更新它的前置条件即源文件和头文件。由于在这个makefile中,.c和.h不是任何rule的target,所以make不进行任何处理。make会更新自动生成的c程序,比如Bison和Y爱Yacc生成的c程序。
重编译需要的目标文件后,make决定是否重新连接edit。如果edit不存在或者目标文件比edit新,则进行重连接。
2.4在makefile中使用变量
在上面的makefile中,我们两次列出了可执行文件edit所需要的目标文件:
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
这种重复很难排错。如果一个新的目标文件加入到系统中,我们可能只在一个地方加入而在另一个地方忘记加入。我们可以通过使用变量来消除这种风险并简化makefile。变量允许定义一次字符串,之后多次替代使用。为每一个makefile生命目标文件列表变量objects,OBJECTS,objs,OBJS,obj,OBJ是最佳实践。我们定义变量objects如下:
objects = main.o kbd.o command.o display.o
insert.o search.o files.o utils.o
有了变量objects之后,我们可以用S(objects)来替代每次需要目标文件列表的地方。下面是用变量替代目标文件列表之后的makefile:
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 : 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 $(objects)
2.5make推导recipe
没有必要在编译单独源文件时声明所有的recipe,因为make可以自动推导。make包含了根据.c文件使用cc -c更新.o文件的隐式规则。当.c文件以这种方式使用时,它会被自动地添加到前置条件中,因此可以在前置条件中省略.c文件,如下:
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)
这使我们在实践中书写makefile的常用方式。
2.6另一种样式的makefile
当makefile的目标都是隐式规则创建的时候,另一种样式的makefile变得可行。在这种样式的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
2.7清除目录的规则
书写规则的目标不仅仅是编译程序。除此之外makefile可以指示如何做其他任务,比如如何删除目标文件和可执行文件等。一个简单的清除目录的规则如下:
clean:
rm edit $(objects)
实际上,我们可能会以更复杂的方式来书写这一规则,如下:
.PHONY : clean
clean :
-rm edit $(objects)
这防止了make在遇到错误时终止的情况。这种规则不应该放在makefile的头部,因为我们不想缺省运行它。因此,在上面个的makefile中,edit仍然是缺省的goal。clean不是edit的前置条件,当我们运行make命令的时候clean不会进行任何操作。为了运行clean规则,输入make clean。
最后
以上就是纯真方盒为你收集整理的makefile小记的全部内容,希望文章能够帮你解决makefile小记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复