make 工具如 GNU make、System V make 和 Berkeley make 是用来组织应用程式编译过程的基本工具,但是每个 make 工具之间又有所不同。本文将介绍 makefile 的结构,避免如何在创建 makefile 时出现一些一起的错误,并探索如何修复或解决可移植性问题,还为解决突发的问题提供了一些技巧。

大部分 UNIX® 和 Linux® 程式都是通过运行 make 来编译的。make 工具会读取一个包含指令的文档(这个文档的名字通常都是 makefile 或 Makefile,但是后文中我们统一称之为 “makefile”),并执行各种操作来编译程式。在很多编译过程中,makefile 自己完全是由其他软件生成的;例如,autoconf/automake 程式就用来研发编译程式。其他程式可能会需要我们直接编辑 makefile,当然,新的研发还可能需要我们自己编写 makefile。

“make 工具”这个短语可能有些容易引起误解。经常使用的 make 工具至少有 3 个变种:GNU make、System V make 和 Berkeley make。他们都是从早期 UNIX 的一个核心规范发展而来的,每个变种都增加了一些新特性。这就导致出现了一种复杂的情况:很常用的一些特性,例如在 makefile 中通过引用来包含其他文档,都不能很好地移植!简单编写程式来创建 makefile 就是一种解决方案。由于 GNU make 是免费的,并且能够广泛地发布,因此有些研发人员就简单地为他来编写代码;类似地,有很多起源于 BSD 的项目都需要我们使用 Berkeley make(这也是免费的)。

稍微逊色一点但依然相关的 make 工具是 Jörg Schilling 的 smake 和 make 家族中的第五位(已不再使用) —— 早先的 make,后者定义了和其他 make 工具共享的一些公共特性的子集。尽管 smake 在任何系统上都不是默认的 make 工具,但是他也是个很好的 make 实现,有些程式(尤其是 Schilling 的程式)都喜欢使用他。

下面先来回顾一下在使用 makefile 时所碰到的最常见的一些问题。

理解 makefile

要调试 make,需要读取 makefile。正如所了解的那样,makefile 的目标就是为编译程式提供一些指令。make 的主要特性之一就是 依赖性管理:只有在程式源码发生更新必须要重新编译程式时,make 才会真正重新编译程式。通常,这是通过一系列依赖性规则来表示的。其中一种依赖性规则如下所示:


清单 1. 依赖性规则的格式
target: dependencies

            instructions

            

人们在编写自己的第一个 makefile 时所碰到的主要问题在这个结构中可能看得出来,也可能看不出来:缩进使用的是制表符,而不是多少个空格。由于在这种格式中使用空格所产生的 Berkeley make 错误消息对人们也没什么帮助:


清单 2. Berkeley make 错误消息
make: "Makefile" line 2: Need an operator

            make: Fatal errors encountered -- cannot continue

            

GNU make,尽管不能对这个文档进行处理,但却会给出一个更有用的建议:


清单 3. GNU make 错误消息
Makefile::2: *** missing separator (did you mean TAB instead of 8 spaces?).  Stop.

            

请注意依赖性和指令都是可选的;只有目标和冒号才是必须的。那么既然语法是这样,语义又该如何呢?其语义是:假如 make 希望编译 target ,那他就会首先查看依赖关系。实际上,他会递归地尝试编译目标;假如所依赖的内容碰巧又依赖其他内容,那么在这条规则继续之前,必须对所依赖的内容进行处理。假如 target 存在,并且至少比 dependencies 中所列出的任何内容都要新,那么就不会执行任何操作。假如 target 不存在,或有一个或多个依赖内容更新,那么 make 就会执行 instructions 操作。依赖性是按照指定的顺序进行处理的。假如没有指定依赖性,那就总会执行 instructions。所依赖的内容也称为 源(source)

假如在命令行中给出了一个目标(例如 make foo),那么 make 就会试图编译这个目标。否则,他就试图编译文档中列出的第一个目标。一些研发人员采用的约定是让第一个目标看起来如下所示:


清单 4. 通常使用的第一个目标约定
default: all

            

有些人会假设之所以使用这条规则是因为他是 “默认的”。但实际上并非如此;他之所以这样使用是因为这是该文档中的第一条规则。能够按照自己希望的方式对其进行命名,但是名字 “default” 是个很好的选择,因为这对于读者来说意义是显而易见的。记住 makefile 是会由人来阅读的,而不是只由 make 程式来使用的。

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!