内容简介: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 章节中可以找到:
-
elf头中自带的 rpath-link 或 rpath 变量
- rpath-link 对可执行文件无效
-
环境变量
LD_RUN_PATH
、LD_LIBRARY_PATH
、-L
(macOS) -
默认路径:
/lib
和/usr/lib
-
根据
/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 时会自动加上。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 项目用 GoModules 管理依赖的方法和经验总结
- 浅析依赖倒转、控制反转、IoC 容器、依赖注入。
- Angular 4 依赖注入教程之五 FactoryProvider配置依赖对象
- Gradle构建SpringBoot程序依赖管理之依赖版本自动控制
- Maven学习笔记七【可选的依赖项和依赖项排除】
- 模块化解耦框架RxFluxArchitecture4-依赖库与依赖注入
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。