Eric Raymond 写了一个工具,用来帮助那些无畏的“代码考古学家们”理解“古代”代码的结构。它叫做 ifdex,它的背后有一段故事,拿起你的 Fedora 和赶牛的鞭子,让我讲给你听……
在开发 NTPsec 早期, 我们就决定替换它的构建系统——它是如此的难于理解和修改——严重的拖慢了我们的开发进度。
古老的 autoconf 构建方式就像一个恐怖的爬行动物,而 NTP 更是一个极端的例子。不完善的宏技术定义了太多的配置符号,为了掌握这些接口,即使你查看了 config.h 也无济于事。尤其是当你要做一些大的修改时,这更是一个问题!
我们的一个伙计 Amar Takhar,是 waf 构建系统的专家,当他初步提出迁移的想法时得到了我的积极响应。几个月之后,他就做出了一些 waf 功能,虽然还未完成,但是已经至少可以生成用于实际测试的二进制了。
这里我说“未完成”的意思是,代码里面还有一些 waf 构建绝不会设置的 #define 。很多人绝对不会碰那些 autoconf 构建的东西,而另外一些人则不。那些从来用不到的配置开关迷失在大堆的系统头文件和编译器设置的 #define 条件中。
我这里说的不是几个或几十个,我最终统计出了有超过 670 个不同的 #define 用在 #if/#ifdef/#ifndef/#elif 条件中,而这些条件,如 John D. Bell 指出的那样,有 2430 个之多。我需要一些办法来检查它们并分成不同的类型:有的来自系统头文件、有的是配置开关,以及其它的……
所以我写了一个分析器,它可以对代码树解析每个编译时条件的符号,然后将它们分成单纯的列表或 GCC 类的文件/行错误信息,你可以用 Emacs 的编译模式逐个分析。
为了降低干扰,它掌握着一个条件符号的长列表(大概200个),这些可以忽略掉。比如像 __GNUC__ 符号是 GCC 预定义,而 O_NONBLOCK 宏用于几种系统调用等等。
这些符号分成几组,你可以使用命令行选项分别忽略它们。所以,如果你希望忽略列表中所有标准的 POSIX 宏而想看到操作系统相关的任何东西,那就可以做到了。
另外一个重要的功能是你可以构造你自己的排除列表及注释。这样当我探索 NTP 编译条件的黑暗森林时,所构造的越来越大的排除列表就代表了我已经了解了的条件符号。最终(我希望)未知符号的报告将缩减为空,那么我就已经了解了所有配置开关的确切意义了。
目前为止,我已经搞定了它们之中的 300 个,还有 373 个。这是我用我的漂亮工具在一周内完成的主要工作。噢,从来没有人说过代码考古是如此的容易。
最后, ifdef 的主页是: http://www.catb.org/esr/ifdex/ ,代码库在这里: https://gitlab.com/esr/ifdex 。希望你用的上。