Monday, January 28, 2019

编译链接错 - 程序员逃不掉的梦魇


编译链接错 - 程序员逃不掉的梦魇
- 记一次调试经历


"Error: Undefined reference to xxxx"
       相信每一个程序员对于这样的错误并不陌生,多少次,接二连三的错误提示如同死亡缠绕一般挥之不去,如影随形。
    
       近期遇到了一个比较坑的链接错,记录下来解决的过程。作为经验的累积,也为在同一条路上苦苦挣扎的程序提供一些参考。

       问题描述:编译程序A,其中用到了grpc以及protobuf,编译时需要链接相应的库。具体来说,需要如下链接如下几个库:-lgrpc++ -lgrpc++_error_details -lprotobuf
      但是在Linux平台下,链接时总是报错未定义引用,比如: undefined reference to `gpr_log'. 可是grpc明明我已经安装了,系统目录下确实存在并且囊括了几乎所有的grpc静态以及动态链接库文件。LD_LIBRARY_PATH中也包含了系统库文件目录路径。

       调整链接库的顺序会产生不一样的连接错误,一开始以为grpc的库和其他库之间存在循环依赖,所以思路一致放在调整库链接的顺序上,以期能解决循环依赖的问题,但无果。百思不得其解。诡异的是,同样的程序在mac下可以编译成功。
        但是诡异的事情往往暗藏玄机。既然编译选项相差无几,mac下可以编译,而linux下不能编译,是不是意味着在Linux下链接的库有问题。用nm神器看下Linux下生成的静态链接库文件,果然找不到提示错误中的符号;但是在mac下却可以找到。所以印证了之前的想法,意味着Linux下的库文件编译有问题。

       可是我下载的grpc的源代码都是一样的啊,等等,唯一不一样的好像是:官方文档里,编译grpc是在grpc源码根目录下直接make,而在Linux平台下,我之前是通过cmake去配置然后make编译的。会不会是这个引发的问题?于是按照官方文档的方法重新make并且更新了Linux平台系统目录下的库文件。这一次,我用nm能找到符号了。重新编译软件A,一切如“丝般润滑”。

       至此,问题解决了。可是回想一下这个问题的解决过程,一开始如果能够早点在mac做一些简单验证,就可以排除循环依赖这个因素而省去很多时间和精力在无谓的事情上。在此之后,通过对比mac和Linux下库文件符号差异,直观感觉可能是grpc链接库本身的问题,才找到了解决方法,但是如果没有mac平台作对比,能不能想到是grpc的问题呢?恐怕没那么容易。

      所以,经验和教训就是:
      1. 快速定位问题。用简单易行的方法快速验证,用排除法,尽快排查掉无关因素;
      2. 抽丝剥茧,顺藤摸瓜,思维不要局限在问题发生的范围内。事出必有因,有时候也需要从源头上找原因。

以上。


No comments:

Post a Comment