第15条:查看第三方组件的源代码,以了解其用法
我们所要调试的代码之所以会出bug,通常并不是由于它使用的第三方程序库或应用程序本身有问题(参见第14条),而是因为它使用这些第三方组件时所采取的方式有误。
这种情况并不令人惊讶,由于这些软件本身是作为黑盒来与你所写的代码进行集成的,因此,你不太可能在它们之间相互协调。对于这类问题来说,有一个很有用的办法,就是去查看第三方程序库、中间件甚至是底层软件的源代码。
首先,如果想查明某个API为什么没有像你所期望的那样运作,或是想查明某条奇怪的错误消息是从哪里发出来的,那么可以浏览第三方组件的源代码,并搜寻其中你所感兴趣的那一部分,以寻求答案。如果想对某个与程序库有关的功能进行调试,那么可以在第三方代码中寻找相关函数或方法的定义,然后由此继续向下查看。在查看第三方程序库的代码时,我们可能并不是要在其中寻找bug,而是想更好地理解它的工作原理以及它与你所写的代码之间的配合方式。如果想知道某条错误消息是从哪里来的,那么可以在整个代码库里面搜寻这条消息,并检查有哪些代码会发出这条消息(参见第23条和第4条)。为了能够迅速地查询函数或方法,我们可以用ctags或etags程序为代码编制索引(大多数编辑器都支持这两个程序所输出的索引),也可以采用集成开发环境(IDE)来查看代码。与ctags相比,IDE能够更好地处理复杂的语言特性,如重载、覆盖以及模板等,而ctags的优势则在于支持的语言数量比较多,5.8版本支持41种语言。在存放源代码的目录里面运行下面这条命令,可以给其中的所有文件创建索引:
如果你所使用的第三方组件是开源的,那么也可以通过Black Duck Open Hub Code Search这样的托管服务来进行搜索。
还有一种更为强大的调试技术,需要我们先构建带有调试信息的第三方组件(参见第28条),然后把自己的代码与这个调试版的第三方程序库相链接。这样,我们就可以像调试自己的代码那样,轻松地在第三方程序库的代码里面进行单步调试了,而且我们还可以使用符号调试器(symbolic debugger,参见第4章)来检视其中的变量。请注意,某些厂商(如Microsoft)在发行其代码的时候,会把供调试所用的版本或带有符号的版本也随着普通版本一起发布出来,这样我们就不用自己去构建包含调试信息的程序库了。
如果bug确实是由第三方代码而非自己的代码所引起的,那么在能够访问其源代码的前提下,你可以对此进行修改。请注意,只有在极其特殊的情况下,才需要使用这种办法,也就是说,只有在既找不到合理的权宜方案又联系不到厂商来对此进行修复的时候,才可以考虑修改第三方程序库的源代码。一旦你这么做,就必须在整个应用程序的生命期内,对该程序库的所有后续版本都做出相应的修改。此外,你还需要保证这样的改动不会违背相关的法律条款。例如,某些厂商在发布代码的时候,会在其协议中要求“只能看,不能改”(look, don’t touch)。对于开源软件来说,比较合理的一种做法,是将修改后的代码提交给负责该代码的项目,而且从道理上来讲,你也确实应该这么做。如果项目托管在GitHub上,那么只需要发起pull request就可以了。
要想运用上面提到的技术,我们必须先获取到第三方组件的源代码。如果第三方程序库或应用程序是开源的,那么很简单,只需要点一下按钮,就可以把源代码下载下来了。对于开源的操作系统发行版,还可以把源代码作为软件包来下载,例如,在Debian Linux系统中,我们可以通过以下命令安装C语言程序库的源代码:
此外,很多软件开发平台也会将其源代码中较为重要的那一部分,安装到你的系统上面。例如,Microsoft的Visual Studio会把C语言运行时库的源代码放在VC\crt\src里面,而Java Development Kit(JDK)则会把源代码放在名为src.zip的压缩文件中。对于其他一些第三方软件来说,你可以在订购软件时支付额外的费用以获取其源码。只要售价不高,我们就应该考虑这么做,若是等以后再去买,则要花很多时间来安排款项,而且还要下订单并执行所需的合约。等到那个时候,软件厂商或许已经不再支持你所使用的版本了,甚至有可能已经停业了。因此,我们应该考虑提前获取这些专有软件的源代码,以免出现此类问题。
要点
如果你依赖某个第三方组件,那么就应该获取其源代码。
通过查看第三方组件的源代码探寻与第三方API及一些奇怪的错误消息有关的问题。
要和第三方程序库的debug版本相链接。
只有当其他办法都不可行的时候,才需要对第三方的源代码进行修改。