依赖库的几点总结

栏目: C++ · 发布时间: 5年前

内容简介:gcc 编译好了,执行过程中不免会遇到这种场景:找不到依赖的 .so 文件,linux 提供了 ldd 命令可以查看:能找到的列出来,找不到的写

现象

gcc 编译好了,执行过程中不免会遇到这种场景:

kevin@:cpp$ ./drawing.bin
./drawing.bin: error while loading shared libraries: libopencv_core.so.3.4: cannot open shared object file: No such file or directory

找不到依赖的 .so 文件,linux 提供了 ldd 命令可以查看:

kevin@:cpp$ ldd drawing.bin
        linux-vdso.so.1 =>  (0x00007ffe7ff2b000)
        libopencv_core.so.3.4 => not found
        libopencv_highgui.so.3.4 => not found
        libopencv_imgproc.so.3.4 => not found
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe6540c2000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe653eac000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe653ae2000)

能找到的列出来,找不到的写 not found ,很好。

弄一个正常的看看:

kevin@:2_图像显示$ ldd ShowImage.bin
        linux-vdso.so.1 =>  (0x00007ffdf0aa3000)
        libopencv_core.so.4.0 => /home/kevin/opencv/installation/OpenCV-4.0.0/lib/libopencv_core.so.4.0 (0x00007ffb45137000)
		此处略去100行……

差别很明显了,drawing.bin 和 ShowImage.bin 所依赖的 so 文件一个找不到,一个OK —— 如何造成?怎么解决?

成因

gcc 在编译和链接的过程中,可以送入这样一个参数: -Wl, -rpath=<my_lib_path>

  • -Wl : 表示编译器将后面的参数传递给链接器ld
  • -rpath : man ld 可以查看 ld 拿到这个参数干什么
    • 链接时定位动态库
    • 写入编译出的二进制文件(elf文件),给加载运行时使用

可以使用 readelf 命令从二进制文件中读出这个配置:

不能运行的:

kevin@:cpp$ readelf -a -u drawing.bin|grep rpath
 0x000000000000000f (RPATH)              Library rpath: [/opt/opencv/lib]

能运行的:

kevin@:2_图像显示$ readelf -a 2_ShowImage-4.0.0.bin |grep rpath
 0x000000000000000f (RPATH)              Library rpath: [ /home/kevin/opencv/installation/OpenCV-4.0.0/lib]

当然,你也可以不去配置 rpath 参数,运行时则只会在其他路径下寻找 libs。

其他路径在哪?到底要搜索多少路径?

解决

ld 是 linux 下的链接器和加载器,其实ld是个 shell 的可执行命令,内部使用的是 ld-linux.so ,而它是静态链接的。

kevin@:cpp$ which ld
/usr/bin/ld
kevin@:cpp$ ldd `which ld`
        linux-vdso.so.1 =>  (0x00007fffb8dde000)
        libbfd-2.26.1-system.so => /usr/lib/x86_64-linux-gnu/libbfd-2.26.1-system.so (0x00007f8245ce5000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8245ae1000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8245717000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f82454fd000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f824602a000)
kevin@:cpp$ ldd  /lib64/ld-linux-x86-64.so.2
        statically linked

ld 在加载一个可执行程序的时候,寻找依赖库(libs)是有顺序的,同样使用 man ld 在 rpath 章节中可以找到:

  1. elf头中自带的 rpath-link 或 rpath 变量
    • rpath-link 对可执行文件无效
  2. 环境变量 LD_RUN_PATHLD_LIBRARY_PATH-L (macOS)
  3. 默认路径: /lib/usr/lib
  4. 根据 /etc/ld.so.conf 中指定的路径,比如我本机有这些:
    /lib/x86_64-linux-gnu
    /usr/lib/x86_64-linux-gnu
    /usr/lib/x86_64-linux-gnu/mesa-egl
    /usr/lib/x86_64-linux-gnu/mesa
    /usr/local/lib
    

理解了 ld 的工作原理,解决方法就浮出水面:

用户级方案

ln -s

/lib/usr/lib 下创建软链接,问题是 lib 一多就麻烦了,单个还能玩一玩。

kevin@:~$ ln -s /home/kevin/opencv/installation/OpenCV-3.4.4/lib/libopencv_core.so.3.4 /usr/lib/

LD_LIBRARY_PATH

临时方案:

运行前先设置一下环境变量

kevin@:cpp$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/kevin/opencv/installation/OpenCV-3.4.4/lib
kevin@:cpp$ ./drawing.bin
This program demonstrates OpenCV drawing and text output functions.
Usage:
   ./drawing

永久方案

kevin@cpp$ echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/kevin/opencv/installation/OpenCV-3.4.4/lib" >> ~/.bashrc
kevin@cpp$ source ~/.bashrc

增加 conf

kevin@:~$ tourch /etc/ld.so.conf.d/opencv.conf
kevin@:~$ echo "/home/kevin/opencv/installation/OpenCV-3.4.4/lib" >> /etc/ld.so.conf.d/opencv.conf

开发者方案

前面3个都是二进制文件已经编译好,用户级的解决方案,如果是开发者,则可以修改gcc参数的rpath,达到一劳永逸的效果。

rpath

kevin@:~$ gcc -I... -L... -Wl,-rpath=/home/kevin/opencv/installation/OpenCV-3.4.4/lib ...`
  • qmake 通常不自动设置 rpath
  • cmake 则比较智能,设置 target_link_libraries 时会自动加上。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Linux命令行与shell脚本编程大全 第3版

Linux命令行与shell脚本编程大全 第3版

[美]布鲁姆,布雷斯纳汉 / 门佳、武海峰 / 人民邮电出版社 / 2016-8-1 / CNY 109.00

这是一本关于Linux命令行与shell脚本编程的全方位教程,主要包括四大部分:Linux命令行,shell脚本编程基础,高级shell脚本编程,如何创建实用的shell脚本。本书针对Linux系统的最新特性进行了全面更新,不仅涵盖了详尽的动手教程和现实世界中的实用信息,还提供了与所学内容相关的参考信息和背景资料。通过本书的学习,你将轻松写出自己的shell脚本。一起来看看 《Linux命令行与shell脚本编程大全 第3版》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具