Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->Linux程序设计 ->正文

怎么样调试make

来源:IBM DW中国 作者:Peter Seebach  时间:2007-04-22 点击: [收藏] [投稿]
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 程序来使用的。

伪目标

通常我们可以说,目标的功能是从其他文件中创建一个文件。实际上并非总是如此。大部分 makefile 都至少有两条规则,它们从来都不会创建目标。请考虑下面的示例规则:


清单 5. 示例伪目标
all: hello goodbye fibonacci


 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:Windows 打印管理在Linux 平台实现   下一篇:C 语言中的指针和内存泄漏

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章