声明,本文翻译的是GNU make 3.8.1版用户手册;本手册的原作者是司徒文(Richard M. Stallman),麦家府(Roland McGrath),史密斯(Paul D. Smith)。原手册发布于2006年4月。此为原文下载地址

make概述 编辑

make工具能自动判断一个大程序的哪些部分需要再编译,并且能用命令来执行再编译操作。本文档讨论的GNU make原来是由司徒文与麦家府开发制作的,从3.76版开始由史密斯接管开发工作。

GNU make遵从IEEE 1003.2-1992标准(POSIX.2)第6.2条。

在本文例子中,笔者用的是C语言程序,这是因为C语言最为流行,但读者也可以用make来完成其他编程语言的编译工作,前提是这种语言的编译器能在 shell下运行。当然,make的应用不局限于程序;如果遇到一些任务,这些任务的文件必须随着其他文件或数据的变化而更新,那么读者就可以用make 来应对这些任务。

在使用make之前,请读者先写好Makefile文件,该文件须描述清楚程序文件之间的关系,还要给出更新每个文件的命令。通常,一个程序的可执行文件由OBJ文件来更新,而这些OBJ文件则由源代码编译产生。

只要有合适的Makefile文件,在修改了一些源代码后,只要在Shell命令行下输入:

make

就足以完成所有必要的再编译。make程序通过Makefile的数据库以及诸文件的最后修改时间来判断哪些文件需要更新。对于每个需要更新的文件, make会用数据库中记录的命令来对其操作。

读者可以给make加上命令行参数,以此告诉make哪些文件需要再编译、怎样再编译。参见第九章如何运行make

如何使用本文档 编辑

如果读者是个make新手,或者想阅读大体介绍,那么在阅读每章时只需少量的看前几节,后面几节可以略过。每章的前几节会有该章介绍以及该章的大体信息,而后几节则会包括一些特殊的或技术性的信息。但第二章 make简介是个例外,全章都是介绍性的内容。

如果读者对其他make程序比较熟悉的话,请参阅第十二章 GNU make的特色功能,该章列出了GNU make的增强功能;另外请参阅第十三章 GNU make与标准make不兼容的部分,该章举出GNU make在少数功能上逊色于其他make的例子。

如果需要阅读摘要,请看第九章第七节 选项摘要附录 A 快速参考以及第四章第八节所讲的特殊目标

问题与漏洞 编辑

如果读者发现了GNU make的一些问题或者认为发现了漏洞,那么请与开发者联系;我们不作任何承诺,但我们会尽力解决问题。

在提交漏洞报告之前,请核实漏洞的真实性。另外请认真反复阅读文档,确定文档介绍的应用方法在实际操作中有效,如果文档对功能上的一些问题没有阐述清楚,那么也请提交报告,这些都是文档的“漏洞”!

在提交漏洞报告或者自己解决漏洞之前,请将Makefile文件简化至最小且能体现漏洞问题的程度。然后把Makefile文件连同出错和警告信息一齐发给我们。请勿改动原信息,最好将其剪切复制到漏洞报告中。请确保用以生成最简Makefile文件的命令中不使用非自由软件或者不常用的程序(其实对于这种工具,读者随时都可以用简单的几句Shell命令来测试)。最后,请详述Makefile本应有的预期结果,以便于我们判断问题是否出在文档上。

如果读者发现了一个如假包换的错误,那么可以通过以下两种途径提交报告:一、通过发送电子邮件到:

bug-make@gnu.org

与我们联系;
二、使用我们的在线项目管理来提交报告,网址是:

http://savannah.gnu.org/projects/make/


除了上述的信息以外,请将使用的make完整的版本号一并发给我们;读者可以通过使用命令“make --version”来获取版本信息。请确保报告中包含make所运行机器的硬件信息与操作系统信息;顺便提一句,获取这些信息的一种方法是使用命令 “make --help”,一切尽在命令的最后一行输出中。

make简介 编辑

首先要有一个名为“Makefile”的文件告诉make需要作什么。绝大多数情况下,Makefile主要让make完成编译与链接程序的工作。

本章我们讨论一个简单的Makefile,这个Makefile会编译与链接一个由八个C源代码文件和三个头文件组成的文本编辑器程序。该 Makefile还会告诉make如何在有明确指示的时候运行各种各样的命令(比如说接到清除指示时,make运行删除某些文件的命令)。要阅读更复杂的 Makefile代码,翻至附录C 一个复杂的Makefile实例

当make重新编译该文本编辑器时,所有的C源代码文件都会被重新编译。如果一个头文件被修改,那么为了保证整体程序无损,包含该头文件的所有C源代码文件都必须要重新编译。源代码文件每经过一次编译都会有一个与自己对应的OBJ文件生成。最后,若有源代码文件被重新编译,所有OBJ文件不管是以前生成的还是新生成的,都会被用来链接生成新的可执行文本编辑器程序。

规则大概是什么样的 编辑

一个简单的Makefile所包含的“规则”形式如下

目标 ...:先决条件
     命令
     ...
     ...

目标的名称一般与生成的文件名称一致(像可执行程序和OBJ文件)。目标的名称 也可以是要进行的动作,比如说“clean”(参见第四章第五节 伪目标)。

先决条件是用以生成目标的输入文件,而一个目标往往依赖于多个文件。

命令是make要执行的动作,而一个规则往往要多行命令。请注意:在每个命令前都必须输入一个Tab!一般粗心大意的人容易在这个问题上犯错。

通常有先决条件规则的命令会在先决条件被改动之后执行。但也有一些执行特殊命令的规则没有先决条件,比如说目标“clean”所在的规则就没有先决条件,该规则含有删除命令。

接下来规则会说明与特定规则关联的文件应该何时被操作,如何被操作。然后make执行先决条件中的命令,用以生成或更新目标。此外,规则还可以对何时与如何进行一个动作下令。参见第四章 编写规则

除了规则之外,Makefile文件也可以有其他内容,但一个简单的Makefile只需有规则即可。规则写出来会比模板中所写的略显复杂,但或多或少含有与其一致的部分。

一份简单的Makefile文件 编辑

下面有一份简单易懂的Makefile文件,该文件描述了各种依赖关系:可执行程序edit依赖于八个OBJ文件,八个OBJ文件依赖于八个C源代码文件和三个头文件。

在本例中,所有C源代码文件都包含了“defs.h”头文件,只有定义了编辑命令的C源代码文件才包含“command.h”头文件,而只有只有能改变编辑器缓冲区的低层C源代码文件才包含“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

要用此Makefile删除目录中所有OBJ文件和可执行程序“edit”,请键入:

make clean

在本例中,目标包括,可执行程序“edit”以及OBJ文件“main.o”与“kdb.o”;先决条件也有许多,如“main.c”与“defs.h”;而每个“.o”文件都既为目标,又是先决条件;命令包括“cc -c main.c”与“cc -c kbd.c”。

若目标为文件,则该文件会在其先决条件被改动后重编译与链接。另外,会自动生成的先决条件首先更新。本例中,“edit”依赖于八个OBJ文件;OBJ文件“main.o”依赖于源代码文件“main.c”与头文件“defs.h”。

Shell命令跟随在目标与先决条件的下一行,该命令控制更新目标文件。每个命令行首必须要有Tab键入,以此区分命令行与Makefile中的其他行。(想想看,make全然不知命令是如何工作的,必须由程序员提供命令来更新目标。make所能干的只有执行程序员给出命令,然后再根据命令判断目标文件是否需要更新;如需要,更新之)。

目标“clean”不是一个文件,仅仅是动作的名称而已。因为这个规则不包含其他动作,而且也不是其他任何规则的先决条件,所以,make不会执行此处操作,除非被特别指定。请注意,此规则既非其他规则之先决条件,亦无先决条件,故此规则唯一目的为运行特定命令。目标若只含命令而与其他文件不相关联,则称此目标为伪目标。可参阅第四章第五节 伪目标,了解详情。另外,请参阅第五章第五节 命令中的报错信息,了解如何忽略rm或者其他命令的报错信息。

make如何执行一个Makefie的指令 编辑

在默认情况下,make的工作始于第一个目标(只要这个目标不是以“。”开头的)。此目标称为默认最终目标(如果不想使用这个默认规定,可以在命令行中输入“make 目标名”(参见第九章第二节 用以确定最终目标的参数)或者更改变量(参见第三章第六节 其它的特殊变量)“.DEFAULT_GOAL”以改变默认最终目标)。

上一节简单示例中,默认最终目标是更新可执行程序“edit”,故将其列入规则首位。

因此,输入以下命令:

make

make首先读取本目录的Makefile,而后开始运行第一个规则。在此例中,规则用以重链接“edit”;但在执行这条规则之前,make必须完成所有“edit”依赖的规则,这些规则就是那些OBJ文件;而每个OBJ文件都会运行自己的一套规则,这些规则会通过编译各自源代码的方式来更新每个“.o”文件。如果头文件或者源代码文件的修改时间比依赖其的OBJ文件要晚,或者OBJ文件不存在,那么重新编译就必须要进行。

那些非最终目标之所以会被运行,是因为最终目标与之相关。而与最终目标无关的规则就不会被执行,除非被特指(如“make clean”)。

在重编译一个OBJ文件之前,make会先更新其先决条件,先决条件包括源代码文件与头文件。此例中的Makefile并没有针对源代码文件与头文件的操作,另外这些“.c”与“.h”文件也不是规则的名称,故make在此不做任何事情。但make会自动更新自动生成的C程序,比如说由Bison或Yacc生成的,由此次规则生成的。

在编译完所有需要的OBJ文件后,make会决定是否重链接“edit”。如果“edit”文件不存在或者OBJ文件比“edit”文件要新,则重链接工作一定要作。如果OBJ文件是刚编译出的,其时间晚于“edit”文件,故此时“edit”文件要被重链接。

因此,如果更改了“insert.c”文件再运行make;make会先编译“insert.c”文件生成“insert.o”文件,再链接生成“edit”文件。若更改的是“command.h”,再运行make;make会编译生成“kdb.o”、“command.o”、“files.o”再链接生成“edit”。

用变量简化Makefile 编辑

在上例中,生成“edit”的OBJ文件组被列举了两次(这里在重复一次):

     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


如此重复书写,容易造成错误;另外,若有新OBJ文件加入系统,本应可以只添加新文件而不考虑原有的OBJ文件。若采用变量协助工作,则既可减少出错几率,亦能简化Makefile。变量允许先对一段文本字符串定义,以后需要书写诸OBJ文件时,可以只输入变量而不需要把所有OBJ文件列出(参见第六章 如何使用变量)。

此处,一个习惯性做法是,在每个Makefile中加入名为“objects”、“OBJECTS”、“objs”、“OBJS”、“obj”或者“OBJ”的变量,用以列出全部OBJ文件的名称。在Makefile中,可以用如下方式定义变量“objects”:

 objects = main.o kbd.o command.o display.o \
               insert.o search.o files.o utils.o


定义之后,文件时需要列出诸OBJ文件处可用“$(objects)”代替(参见第六章 如何使用变量)。

下面就是用变量来描述诸OBJ文件的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)

让make自己推算出要执行的命令 编辑

不必将每个编译C源代码文件的命令全部写出,因为make可以构造出这些命令:make有一个隐规则可通过命令“cc -c”生成与“.c”文件前缀名一致的“.o”文件的命令,比如将“main.c”编译成“main.o”的命令“cc -c main.c -o main.o”。此处可以把命令中写“.o”的部分省略。参阅第十章 使用隐规则

当“.c”文件以下例方法自动被使用时,“.c”文件会自动加入到先决条件中。在先决条件中省略“.c”文件的同时,编译命令也被省略了。

下面是个完整的例子。例子中包括了上面两种省略方法,而且也使用了上一节所说的“objects”变量。

  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相差无几(复杂化的“clean”规则在其他地方有所讨论。参见第四章第五节 伪目标第五章第五节 命令中的报错信息)。

隐规则使用简便,故尤为重要。读者会频繁见到隐规则的使用。

另一种格式的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


这里,“defs.h”为所有OBJ文件的先决条件;“command.h”与“buffer.h”为特定OBJ文件的先决条件。

不知这样紧凑的写法是否为一些人的爱好,但还是有一些人不喜欢这种写法,认为将一个目标跟与之对应的信息写在一起显得比较清楚。

清理目录的规则 编辑

编写Makefile所要写的不仅仅编译程序。Makefile还能做一些编译外的事情,比如说,如何将一个目录里的OBJ文件与可执行文件清理干净。

下面就是一例,演示如何用make以完成清除工作:

     clean:
             rm edit $(objects)


在实际应用中Makefile可能会写得更复杂,以应对突发事件,下为例:

.PHONY : clean
     clean :
             -rm edit $(objects)


本例的Makefile,可在有文件名为“clean”时避免混淆,还可在rm报错时仍旧执行。(参见第四章第五节 伪目标第五章第五节 命令中的报错信息

此类规则不可置于Makefile文首,这是由于一般不愿让其作为默认规则执行!故在前几节的完整Makefile示例中,用“edit”为默认规则,以便编译与重编译。

因为“clean”并非“edit”的先决条件,故此规则在make没有参数时不会运行。若要运行此规则,键入命令“make clean”(参见第九章 如何运行make)。

编写Makefile 编辑

make重编译系统的信息源于Makefile构建的数据库。

Makefile裡包含的是什么 编辑

“Makefile”文件应该取什么样的名字 编辑

包含其它的Makefile文件 编辑

“MAKEFILES”变量 编辑

“MAKEFILE_LIST”变量 编辑

其它的特殊变量 编辑

Makefile如可被make再执行 编辑

调用其它Makefile的重要技巧 编辑

make如何理解Makefile的内容 编辑

编写规则 编辑

规则的语法结构 编辑

先决条件的种类 编辑

在文件名中使用通配符 编辑

通配符示例 编辑

使用通配符的陷阱 编辑

“wildcard”函数 编辑

为先决条件搜索目录 编辑

“VPATH”:为所有先决条件搜索路径 编辑

“vpath”指令 编辑

目录搜索是如何进行的 编辑

编写带目录搜索功能的Shell命令 编辑

目录搜索与隐规则 编辑

为连接库而做的目录搜索 编辑

伪目标 编辑

无先决条件与命令的规则 编辑

用目标对应的空文件记录事件 编辑

特殊内建目标的名称 编辑

单规则使用多目标 编辑

单目标对应多规则 编辑

静态模式规则 编辑

静态模式规则的语法结构 编辑

静态模式规则与隐规则的比较 编辑

带双冒号的规则 编辑

自动生成先决条件 编辑

编写规则中的命令 编辑

命令的语法结构 编辑

将命令分为多行的方法 编辑

在命令中使用变量 编辑

输出信息命令 编辑

命令的执行 编辑

选择Shell 编辑

并行执行 编辑

命令中的报错信息 编辑

中断或强制结束make 编辑

递归使用make 编辑

make的变量是怎样工作的 编辑

与低层的make互传变量 编辑

与低层的make互传选项 编辑

“--print-directory”选项 编辑

定义封装的命令组 编辑

使用空命令 编辑

如何使用变量 编辑

变量的基本参考 编辑

变量的两种风格 编辑

变量高级功能参考 编辑

替换功能参考 编辑

可运算的变量名 编辑

变量如何获取其值 编辑

设置变量 编辑

向变量追加文本内容 编辑

“override”指令 编辑

逐字定义变量 编辑

来自环境变量的变量 编辑

目标特定变量的赋值 编辑

模式特定变量的赋值 编辑

Makefile的条件控制部分 编辑

条件示例 编辑

条件的语法结构 编辑

测试标志位的条件 编辑

文本操控函数 编辑

函数调用的语法结构 编辑

对字符串做替换与分解的函数 编辑

对文件名操作的函数 编辑

条件控制函数 编辑

“foreach”函数 编辑

“call”函数 编辑

“value”函数 编辑

“eval”函数 编辑

“shell”函数 编辑

控制make的函数 编辑

如何运行make 编辑

用以确定Makefile文件的参数 编辑

用以确定最终目标的参数 编辑

用其它功能来取代执行命令的参数 编辑

避免重新编译某些文件 编辑

初始变量 编辑

测试编译程序 编辑

选项摘要 编辑

使用隐规则 编辑

使用隐规则 编辑

隐规则章目 编辑

隐规则使用的变量 编辑

隐规则链 编辑

定义与重定义模式的规则 编辑

模式的规则介绍 编辑

模式的规则示例 编辑

自变变量 编辑

模式是如何匹配的 编辑

匹配一切的模式规则 编辑

取消隐规则 编辑

定义去除依赖的默认规则 编辑

过时的附加规则 编辑

隐规则的搜索算法 编辑

使用make更新归档文件 编辑

归档成员作为目标 编辑

为归档成员目标而设的隐规则 编辑

更新归档字符目录 编辑

使用归档的风险 编辑

归档文件的附加规则 编辑

GNU make的特色功能 编辑

GNU make与标准make不兼容的部分 编辑

GNU make的一些不成文规定 编辑

Makefile的通用习惯 编辑

Makefile的工具 编辑

指定变量的命令 编辑

安装目录的变量 编辑

为用户设计的标准目标 编辑

安装命令的条目 编辑

附录 编辑

A 快速参考 编辑

B 常见错误 编辑

C 一个复杂的Makefile实例 编辑

下面是一段为GNU tar程序设计的Makefile代码,相当复杂。

由于“all”是第一个目标,所以它也是默认目标。下面这个程序段有一个非常有趣的特色,这个特色就是源代码程序中的“testpad.h”文件是一个由名叫testpad程序自动生成的,而这个testpad又是又是由“testpad.c”这个程序经过编译产生的。

如果您输入“make”或者“make all”,则make会让名为“tar”的目标运行从而开始编译指令,会让名为“rmt”的目标运行从而生成一个远程磁带数据存取的守护程序,会让名为 “tar.info”的目标运行从而生成INFO文档。

如果您输入“make install”,那么make就执行的就不仅仅只是“tar”、“rmt”和“tar.info”这三个目标了,还会执行相应的安装操作。< /br>
如果您输入“make clean”,那么make会清除所有的“.o”文件,以及“tar”、“rmt”、“testpad”、“testpad.h”和“core”这些文件。

如果您输入“make distclean”,那么make除了会清除“make clean”会清除的文件外,还会清除“TAGS”、“Makefile”和“config.status”这些文件(虽然不明显,但下面这个 makefile和“config.status”都是用户通过tar发行版中的“configure”文件生成的,这个“configure”文件这里没有列出)。

如果您输入“make realclean”,那么make除了清除“make distclean”会清除的文件外,还会清除由“tar.info”生成的INFO文档。

# Generated automatically from Makefile.in by configure.
     # Un*x Makefile for GNU tar program.
     # Copyright (C) 1991 Free Software Foundation, Inc.
     
     # This program is free software; you can redistribute
     # it and/or modify it under the terms of the GNU
     # General Public License ...
     ...
     ...
     
     SHELL = /bin/sh
     
     #### Start of system configuration section. ####
     
     srcdir = .
     
     # If you use gcc, you should either run the
     # fixincludes script that comes with it or else use
     # gcc with the -traditional option.  Otherwise ioctl
     # calls will be compiled incorrectly on some systems.
     CC = gcc -O
     YACC = bison -y
     INSTALL = /usr/local/bin/install -c
     INSTALLDATA = /usr/local/bin/install -c -m 644
     
     # Things you might add to DEFS:
     # -DSTDC_HEADERS        If you have ANSI C headers and
     #                       libraries.
     # -DPOSIX               If you have POSIX.1 headers and
     #                       libraries.
     # -DBSD42               If you have sys/dir.h (unless
     #                       you use -DPOSIX), sys/file.h,
     #                       and st_blocks in `struct stat'.
     # -DUSG                 If you have System V/ANSI C
     #                       string and memory functions
     #                       and headers, sys/sysmacros.h,
     #                       fcntl.h, getcwd, no valloc,
     #                       and ndir.h (unless
     #                       you use -DDIRENT).
     # -DNO_MEMORY_H         If USG or STDC_HEADERS but do not
     #                       include memory.h.
     # -DDIRENT              If USG and you have dirent.h
     #                       instead of ndir.h.
     # -DSIGTYPE=int         If your signal handlers
     #                       return int, not void.
     # -DNO_MTIO             If you lack sys/mtio.h
     #                       (magtape ioctls).
     # -DNO_REMOTE           If you do not have a remote shell
     #                       or rexec.
     # -DUSE_REXEC           To use rexec for remote tape
     #                       operations instead of
     #                       forking rsh or remsh.
     # -DVPRINTF_MISSING     If you lack vprintf function
     #                       (but have _doprnt).
     # -DDOPRNT_MISSING      If you lack _doprnt function.
     #                       Also need to define
     #                       -DVPRINTF_MISSING.
     # -DFTIME_MISSING       If you lack ftime system call.
     # -DSTRSTR_MISSING      If you lack strstr function.
     # -DVALLOC_MISSING      If you lack valloc function.
     # -DMKDIR_MISSING       If you lack mkdir and
     #                       rmdir system calls.
     # -DRENAME_MISSING      If you lack rename system call.
     # -DFTRUNCATE_MISSING   If you lack ftruncate
     #                       system call.
     # -DV7                  On Version 7 Unix (not
     #                       tested in a long time).
     # -DEMUL_OPEN3          If you lack a 3-argument version
     #                       of open, and want to emulate it
     #                       with system calls you do have.
     # -DNO_OPEN3            If you lack the 3-argument open
     #                       and want to disable the tar -k
     #                       option instead of emulating open.
     # -DXENIX               If you have sys/inode.h
     #                       and need it 94 to be included.
     
     DEFS =  -DSIGTYPE=int -DDIRENT -DSTRSTR_MISSING \
             -DVPRINTF_MISSING -DBSD42
     # Set this to rtapelib.o unless you defined NO_REMOTE,
     # in which case make it empty.
     RTAPELIB = rtapelib.o
     LIBS =
     DEF_AR_FILE = /dev/rmt8
     DEFBLOCKING = 20
     
     CDEBUG = -g
     CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS) \
             -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" \
             -DDEFBLOCKING=$(DEFBLOCKING)
     LDFLAGS = -g
     
     prefix = /usr/local
     # Prefix for each installed program,
     # normally empty or `g'.
     binprefix =
     
     # The directory to install tar in.
     bindir = $(prefix)/bin
     
     # The directory to install the info files in.
     infodir = $(prefix)/info
     
     #### End of system configuration section. ####
     
     SRC1 =  tar.c create.c extract.c buffer.c \
             getoldopt.c update.c gnu.c mangle.c
     SRC2 =  version.c list.c names.c diffarch.c \
             port.c wildmat.c getopt.c
     SRC3 =  getopt1.c regex.c getdate.y
     SRCS =  $(SRC1) $(SRC2) $(SRC3)
     OBJ1 =  tar.o create.o extract.o buffer.o \
             getoldopt.o update.o gnu.o mangle.o
     OBJ2 =  version.o list.o names.o diffarch.o \
             port.o wildmat.o getopt.o
     OBJ3 =  getopt1.o regex.o getdate.o $(RTAPELIB)
     OBJS =  $(OBJ1) $(OBJ2) $(OBJ3)
     AUX =   README COPYING ChangeLog Makefile.in  \
             makefile.pc configure configure.in \
             tar.texinfo tar.info* texinfo.tex \
             tar.h port.h open3.h getopt.h regex.h \
             rmt.h rmt.c rtapelib.c alloca.c \
             msd_dir.h msd_dir.c tcexparg.c \
             level-0 level-1 backup-specs testpad.c
     
     .PHONY: all
     all:    tar rmt tar.info
     
     .PHONY: tar
     tar:    $(OBJS)
             $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
     
     rmt:    rmt.c
             $(CC) $(CFLAGS) $(LDFLAGS) -o $@ rmt.c
     
     tar.info: tar.texinfo
             makeinfo tar.texinfo
     
     .PHONY: install
     install: all
             $(INSTALL) tar $(bindir)/$(binprefix)tar
             -test ! -f rmt || $(INSTALL) rmt /etc/rmt
             $(INSTALLDATA) $(srcdir)/tar.info* $(infodir)
     
     $(OBJS): tar.h port.h testpad.h
     regex.o buffer.o tar.o: regex.h
     # getdate.y has 8 shift/reduce conflicts.
     
     testpad.h: testpad
             ./testpad
     
     testpad: testpad.o
             $(CC) -o $@ testpad.o
     
     TAGS:   $(SRCS)
             etags $(SRCS)
     
     .PHONY: clean
     clean:
             rm -f *.o tar rmt testpad testpad.h core
     
     .PHONY: distclean
     distclean: clean
             rm -f TAGS Makefile config.status
     
     .PHONY: realclean
     realclean: distclean
             rm -f tar.info*
     
     .PHONY: shar
     shar: $(SRCS) $(AUX)
             shar $(SRCS) $(AUX) | compress \
               > tar-`sed -e '/version_string/!d' \
                          -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
                          -e q
                          version.c`.shar.Z
     
     .PHONY: dist
     dist: $(SRCS) $(AUX)
             echo tar-`sed \
                  -e '/version_string/!d' \
                  -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
                  -e q
                  version.c` > .fname
             -rm -rf `cat .fname`
             mkdir `cat .fname`
             ln $(SRCS) $(AUX) `cat .fname`
             tar chZf `cat .fname`.tar.Z `cat .fname`
             -rm -rf `cat .fname` .fname
     
     tar.zoo: $(SRCS) $(AUX)
             -rm -rf tmp.dir
             -mkdir tmp.dir
             -rm tar.zoo
             for X in $(SRCS) $(AUX) ; do \
                 echo $$X ; \
                 sed 's/$$/^M/' $$X \
                 > tmp.dir/$$X ; done
             cd tmp.dir ; zoo aM ../tar.zoo *
             -rm -rf tmp.dir

D GNU 自由文档许可证 编辑

GNU 自由文档许可证