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

程序编译中怎么样调试configure

来源:IBM DW中国 作者:Peter Seebach  时间:2007-04-22 点击: [收藏] [投稿]
通常,在软件包的 README 文件中只能找到非常简单的“编译说明:运行 configure,然后运行 make”。但是,这样行不通时怎么办?在本文中,Peter Seebash 讲述了当自动的配置脚本失效时应该怎么样去做——以及作为开发者您应怎么样尽量避免这种错误。毕竟,如果您的程序无法编译,其结果将和您的程序编译后不能运行一样,您的用户会减少。

现在许多开放源代码的程序都会附带有 configure 脚本。这种脚本的用途之一是自动进行对目标新系统的猜测过程。在过去,程序会附带一个 Makefile 文件,这个文件中有 6 个不同的编译标记和选项,但只会用到一个,其余全部注释掉,并且会有一个注解,告诉您“为您的系统选择合适的标记”。如果配置选项更复杂,可能还会有一个名为 config.h 的长长的 C 头文件,其中包含一些要设置的标记,这依赖于主机系统变量。

第一个方法很简单,在代码中使用 #ifdef 以支持两种系统,例如 BSD 和 System V。由于 Unix 的类型的增加,更为实用的方法是对每一个特性使用 #ifdef 。每个系统的代码如下:


清单 1. 每个系统的代码

    #ifdef SUNOS4 || NEXT || NETBSD || FREEBSD || OPENBSD
    #include <string.h>
    #else
    #include <strings.h>
    #endif

每个特性的代码如下:


清单 2. 每个特性的代码

    #ifdef HAS_STRING_H
    #include <string.h>
    #else
    #include <strings.h>
    #endif

后者更容易适应新系统,但需要开发者进行大量的工作。由于现在有太多可能的目标系统,因此,第二种方法对用户来说帮助很大,不仅仅是可以自动生成配置头文件。完成这项任务的一种方法是使用 GNU autoconf 代码来生成 configure 脚本。这个脚本会去执行必要的测试,并创建一个具有适当值的配置头文件。

这种脚本的另一个功能是以一致的方式设置预定义的变量。用手工编辑标记一直存在一个问题,即修改了 Makefile 文件(比如将其安装到 /usr/gnu 而不是 /usr/local 目录下)却忘记修改头文件中相应的值。当然,这样的结果是,编译后的程序不知道到哪里去寻找它们自己的数据文件。使用 configure 脚本的一个好处是可以自动完成一致的安装(如果维护者做得没错的话)。

开发人员请注意,一个好的 configure 脚本的另一个好处在于,它会允许用户指定一些个人偏好,例如使用 /usr/gnu 而不是 /usr/local。

最后, configure 脚本可以完成大量猜测工作,即安装了哪些可选软件包或缺少哪些必要条件。例如,一个设计运行于 X Window System 的程序需要知道 X 安装在哪里,或者甚至要知道 是否安装了 X。

这些怎么样成为可能?

编译,再编译

configure 的许多功能实现机制其实很简单。为了能切身体会,您可以设计一个小测试程序,这个程序当且仅当期望的条件得到满足时才可以编译。将它保存在一个临时文件中,然后尝试编译它。例如,假定您想知道 X Windowing System 是否安装在 /usr/X11R6 目录下。一种方法是做一个如下的测试程序:

#include <X11/X.h>
int main(void) { return 0; }

现在,如果您用编译器来尝试进行编译,那么只有当 <X11/X.h> 在编译器的 include 路径中时,编译才会成功。因此,对每一个您认为 X 可能安装到的目录,可以将对应的 (directory)/include 加入到编译器的 include 路径中,并尝试对程序进行编译。如果采用某个值时示例文件可以编译,那么您就得到了正确的 include 路径。

请注意在 autoconf 中已经预定义了各种测试程序。如果可能,就直接使用这些测试程序,而不用自己去写。这样有很多好处。首先, autoconf 的新版本会改进这些测试程序,修正它们的错误,否则您将不得不自己去做这些工作。其次,这样会节省您的时间。当然,更好的方法是完全避免测试。如果您确认某一个测试是没有必要的(例如,即使机器字节多于 8 位也仍需要使 sizeof(char) 为 1),您可以完全不去进行这个测试。

有一些测试是功能测试;它不足以确定是否存在一个名为 memcmp() 的函数,它的语义必须正确。通常,这些测试用于只是在一两个平台上被注意到的非常不明显的错误。这些测试实际上会去运行测试程序,并检查它的输出。测试程序遵循标准的 Unix 习惯:如果测试通过则返回值为 0,如果失败则返回一个非 0 值。

一旦您有了足够的测试程序,您可以用它们来自动确定必需的编译标记和定义,以将它们放到头文件的某个地方。通常, configure 脚本会允许用户给出部分或全部已知的条件,而不是让脚本自己去猜测。

来看一个特例,假定,系统的 broken memmove() 出现了问题。如果您不知道它现在有一个只会影响少部分程序的 bug,您可能会编译一个程序并将其发布为产品,而没有意识到这样您将会遇到偶然的灾难性错误。

在许多情况下,一个冗长而复杂的 configure 脚本的最终结果是这样的:目标系统提供了这个程序用到的每一个标准特性,而且它们正确工作。在这种情况下为什么不手工去设置这些标记呢?这对开发者来说是可行的,而对众多用户来说就不可以了。用户可能不会知道到他们的 Linux 版本存在特定的 bug。他们可能不知道已经安装了哪些软件包,或者安装到了何处。脚本帮那些最需要帮助的人来完成大部分的例行公事的工作。当脚本出错时,引发的额外工作的代价可能不会太大。

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



上一篇:在Perl 中使用内联   下一篇:使用自由软件Rexx 的实现来编写脚本

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号