记一次编译错误的解决过程

最近开发新的需求需要使用某个外部模块的库文件,该模块在文档中提供了一个demo,但makefile文件编译报错。通过摸索和学习最终把demo编译成功并运行起来,下面记录一下过程中碰到的问题并进行总结。

so not found

使用gcc编译c/c++程序时,编译时用-I指定头文件查找路径,-L指定库文件查找路径,-l具体指定依赖的库。

如果指定了-L,也使用-l链接了该库,但是报如下告警:

1warning: libxxx.so, needed by ./libyyy.so, not found (try using -rpath or -rpath-link)

说明该so依赖的其他so无法找到。使用ldd命令查看该so依赖的所有其他so,会有类似于

1/usr/bin/ld: cannot find -lxxx

的打印,这时就需要找到被依赖的so所在的绝对路径,添加到/etc/ld.so.conf文件中,并执行ldconfig

另一种办法是向环境变量LD_LIBRARY_PATH中添加路径,指定动态库加载路径;对应的静态库加载路径的环境变量名LIBRARY_PATH

注意: 使用env命令查看系统中若无环境变量LD_LIBRARY_PATHLIBRARY_PATH,则需要使用export命令将变量变成环境变量,即该变量在子shell进程中也可见。但重新登录时该环境变量会消失。要想环境变量每次登录都存在,可以向/etc/profile文件尾用export添加环境变量。这是因为每次登录时系统会自动执行/etc/profile脚本

file format not recognized

编译时提示错误如:

1/usr/bin/ld:./libxxx.so: file format not recognized; treating as linker script
2/usr/bin/ld:./libxxx.so:2: syntax error

意思是这个so文件格式不识别,ld试图将它当作链接文件来看待,但仍然出错。查看发现该so文件大小只有几字节,且附近有一个带后缀.1的文件libxxx.so.1。原因是该so文件实际是一个软链接文件,链接对象就是libxxx.so.1;但由于该模块提供的lib压缩包是在windows下解压后通过远程文件系统挂载到linux系统上的,软连接文件被当成普通文件解压了。解决办法是重新创建软连接或直接在linux下解压。

so后面带的.1是版本号为1的意思。这是linux下动态库版本控制的一种方法。具体可以看动态链接库的版本控制一文。

undefined reference to

undefined reference to 即未定义的引用,表示某函数被声明了但是却没有找到对应的实现,这种情况是可以编译成功的,但是链接会失败。类似的还有Undeclared references,即未声明的引用,表示找不到函数声明。

出现这种情况只能考虑是编译时还有必要的库没有链接,对库文件夹中所有的库执行nm命令,过滤该函数名,找到该函数定义(T类)所在的库文件,并将其加入到编译链接库中。

nm用于打印库或可执行文件中的符号名:

  • T类:是在库中定义的函数,用T表示;
  • U类:是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;