前言,linux的动态库是经常要用的,我们大致知道动态库是运行的时候加载到程序里面去,但是,即使如此,动态库的编译也需要有严格的头文件和依赖相关性。于是,构建系统编译项目的时候,经常会遇到动态库找不到,或者动态库不匹配(包括版本,包括内建函数,标号等)造成的编译错误。有时候,即使编译通过,在实际运行执行文件的时候,一些隐晦的动态库还是会跳出来。所以,如何,审视动态库的内建标号,以及版本和依赖性是非常必要的。掌握了方法,可以大大缩短工程时间。

本文在一篇博文基础上做了修改。

1 动态库的路径设定

1.1 Linux动态库的默认搜索路径是/lib和/usr/lib

当程序执行时需要加载某动态库,系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函数,以及该动态库的其它资源了。

1.2  在配置文件/etc/ld.so.conf中指定动态库搜索路径。

可以通过编辑配置文件/etc/ld.so.conf来指定动态库的搜索路径,该文件中每行为一个动态库搜索路径。每次编辑完该文件后,都必须运行命令ldconfig使修改后的配置生效。我们通过例1来说明该方法。

1.3 通过环境变量LD_LIBRARY_PATH指定动态库搜索路径。

通过设定环境变量LD_LIBRARY_PATH也可以指定动态库搜索路径。当通过该环境变量指定多个动态库搜索路径时,路径之间用冒号":"分隔。

1.4 在编译目标代码时指定该程序的动态库搜索路径。

在编译目标代码时指定程序的动态库搜索路径。这是通过gcc 的参数"-Wl,-rpath,"指定。当指定多个动态库搜索路径时,路径之间用冒号":"分隔。当链接某个程序时,在运行期您可以指定另外的搜索路径。在 gcc 中,其 语法是 -Wl,-R/path。下图,是一个编译前,在gyp文件里面增加路径的设定例子。

'ldflags': [
'-Wl,-rpath-link,-L/project/arm/<(workfolder)/customer/usr/local/lib',
]

2 查询动态库的依赖相关命令:ldd

ldd命令的作用是查看程序依赖的动态链接库信息。使用nm命令也可以获取库函数的信息;nm命令可以列出一个函数库文件中的符号表,它对静态的库函数和共享的库函数都能起作用。

ldd的作用是打印可执行档依赖的共享库文件。它是glibc的一部分,由Roland McGrath和Ulrich Drepper维护:
$ ldd --version
ldd (GNU libc) 2.9
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

但是ldd本身不是一个程序,而仅是一个shell脚本:
$ which ldd
/usr/bin/ldd
$ file /usr/bin/ldd 
/usr/bin/ldd: Bourne-Again shell script text executable

ldd命令其实是依靠设置一些环境变量而实现的(也就是说ldd的作用只是设置一些环境变量的值)
如:LD_TRACE_LOADED_OBJECTS
只要设置其值非空即可。
$ export LD_TRACE_LOADED_OBJECTS=1
$ ls /usr
linux-gate.so.1 =>  (0xb7fac000)
librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7f93000)
libselinux.so.1 => /lib/libselinux.so.1 (0xb7f79000)
libacl.so.1 => /lib/libacl.so.1 (0xb7f70000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e0d000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7df4000)
/lib/ld-linux.so.2 (0xb7fad000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7df0000)
libattr.so.1 => /lib/libattr.so.1 (0xb7dea000)

撤销该环境变量,ls即又可以恢复正常使用:
$ unset LD_TRACE_LOADED_OBJECTS
$ ls  /usr/
bin  games  include  lib  lib32  lib64  local  sbin  share  src  X11R6

更多的环境变量:
1、LD_TRACE_LOADED_OBJECTS
2、LD_WARN
3、LD_BIND_NOW
4、LD_LIBRARY_VERSION
5、LD_VERBOSE
6、LD_DEBUG

ldd默认开启的环境变量是:LD_TRACE_LOADED_OBJECTS=1
其他的变量(和值)分别对应一些选项:
-d, --data-relocs -> LD_WARN=yes
-r, --function-relocs ->LD_WARN和LD_BIND_NOW=yes
-u, --unused -> LD_DEBUG="unused"
-v, --verbose -> LD_VERBOSE=yes
LD_TRACE_LOADED_OBJECTS为必要环境变量,其他视具体情况。

更为详细的命令选项(或者参看man、info):
$ ldd --help
Usage: ldd [OPTION]... FILE...
--help              print this help and exit
--version           print version information and exit
-d, --data-relocs       process data relocations
-r, --function-relocs   process data and function relocations
-u, --unused            print unused direct dependencies
-v, --verbose           print all information
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

但是ldd命令的本质是执行了:/lib/ld-linux.so.* 
我们可以从以上的内容中(ls /usr中)发现:/lib/ld-linux.so.2 (0xb7fad000)。
$ ls -l /lib/ld-linux.so.* 
lrwxrwxrwx 1 root root 9 2009-09-05 22:54 /lib/ld-linux.so.2 -> ld-2.9.so
刚编译后的文件可能是:/lib/ld.so。如果是libc5则是/lib/ld-linux.so.1, 而glibc2应该是/lib/ld-linux.so.2。

$ /lib/ld-linux.so.2  --list /bin/ls
linux-gate.so.1 =>  (0xb8050000)
librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb8037000)
libselinux.so.1 => /lib/libselinux.so.1 (0xb801d000)
libacl.so.1 => /lib/libacl.so.1 (0xb8014000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7eb1000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7e98000)
/lib/ld-linux.so.2 (0xb8051000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7e94000)
libattr.so.1 => /lib/libattr.so.1 (0xb7e8e000)
我们可以看到以上等同于ldd ls。/lib/ld-linux.so.2还有其他一些选项:
1、--verify 
2、--library-path PATH
3、--inhibit-rpath LIST

ldd可以获得的共享库文件,其实是通过读取ldconfig命令组建起来的文件(/etc/ld.so.cache)。
默认的共享库文件搜索/lib优先于/usr/lib,而且也只有这个2个目录。如果想要加入其他路径,则需要通过ldconfig命令配置相关文件。
一般ld-linux.so会按照以下顺序搜索共享库:
1、DT_RPATH或DT_RUNPATH段
2、环境变量LD_LIBRARY_PATH
3、/etc/ld.so.cache文件中的路径,但如果可执行程序在连接时候添加了-z nodeflib选项,则跳过。
4、默认路径/lib和/usr/lib,但如果添加了-z nodeflib,则跳过。

还有一些额外的环境变量可以参看man ld.so。

更为详细的内容:
1、man ldd(http://www.kernel.org/doc/man-pages/online/pages/man1/ldd.1.html)
2、man ldconfig(http://www.kernel.org/doc/man-pages/online/pages/man8/ldconfig.8.html)
3、man ld.so(http://www.kernel.org/doc/man-pages/online/pages/man8/ld.so.8.html)

可以参见的文章:
1、Linux 动态库剖析(http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/)
2、剖析共享程序库http://www.ibm.com/developerworks/cn/linux/l-shlibs.html)

3、ldd命令的原理与使用方法(http://hi.baidu.com/wstone_h/blog/item/af67700a80a01e1594ca6b29.html)

REF:

ldd命令,查看依赖的动态库信息 nm命令可以列出一个函数库文件中的符号表

https://my.oschina.net/lieefu/blog/548299

[linux]【编译】【高级01】 - 动态库的设定和依赖性的检查 20160921更新 文章没有最终结案相关推荐

  1. 树莓派linux编译不了动态库,linux系统下的树莓派与Qt 5.12.3源码的交叉编译

    {写在前面:按照这个方法,基本可以成功在linux系统下交叉编译Qt5.12.3,其他版本的源码也编译} 我的环境:Linux Mint 19.1;树莓派 3;Qt源码5.12.3 当两个系统全部安装 ...

  2. linux动态库路径生效,Linux下如何解决动态库的链接问题

    原标题:Linux下如何解决动态库的链接问题 静态库是一种以空间换取时间和移植性的做法,一些情况下确实有着一定的意义,但是一些情况下,我们自己编写的简单项目,在绝大多数的机器上不存在移植性问题,是没有 ...

  3. FFmpeg编译成Android动态库

    项目需要,网上也有现成的FFmpeg Android动态库,但是本着亲力亲为的宗旨,做了不断地尝试,最终也是成功了,在此做一个笔记,以备日后查阅. 附上给我帮助的资料链接: 王英豪大神的博客 雷霄骅大 ...

  4. 嵌入式linux学习笔记-- 对于动态库的一些操作 dlopen

    最近公司重构代码,看到了公司的一位经验丰富的工程师的一些C++ 操作 属实有被秀到,估计光看他写的代码都够我写很多总结了. 根据他写的代码以及公司未来的代码的一些规划 我也总结一些无关痛痒的知识吧. ...

  5. linux平台 加载动态库dlsym返回null

    linux 平台加载动态库通常使用dlopen,dlsym,dlclose三个函数实现 最近写了一个小程序,遇到dlsym总是调用失败返回空值,查找了很多相关的资料,确定动态库的创建有问题.下面是最初 ...

  6. Linux系统中的“动态库”和“静态库”

    Linux系统中的"动态库"和"静态库" 在Linux操作系统中,普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式.ELF(Executable a ...

  7. Linux系统中的动态库和静态库

    来源:  wjlkoorey258 链接:  http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库 ...

  8. ViSP安装之Windows系统基于VS2019编译器编译获得VISP动态库

    Windows系统基于VS2019编译器编译获得VISP动态库 官网地址: Installation from source for Windows with Visual C++ 2019 (vc1 ...

  9. 【Android 逆向】修改运行中的 Android 进程的内存数据 ( Android 系统中调试器进程内存流程 | 编译内存调试动态库以及调试程序 )

    文章目录 一.Android 系统中调试器进程内存流程 二.编译内存调试动态库以及调试程序 三.博客资源 一.Android 系统中调试器进程内存流程 修改游戏运行中的内存 , 游戏运行之后 , 游戏 ...

最新文章

  1. 人工智能乌托邦 迪拜认为2071年人类应该这样生活!
  2. JavaScript常规语法小总节
  3. JS操作DOM元素属性和方法
  4. 10000 字讲清楚 Spring Boot 注解原理
  5. Android 应用软件开发(九)控件续
  6. Android VideoView
  7. 分频器+计数器+数码管显示VHDL
  8. TPC-DS生成数据
  9. 什么是PLC软元件和软继电器
  10. Latex的常见错误
  11. Unity3D连接本地或局域网MySQL数据库
  12. 用C++实现渊子赛马程序
  13. 数据库学习之多种数据库横向对比
  14. Android百度AI植物识别教程,微信开发+百度AI学习:植物识别(示例代码)
  15. 【相机硬触发】大恒相机硬触发说明文档
  16. 学习小记 -- 线程池的工作原理
  17. 如何添加计算机硬盘分区,怎么给电脑硬盘增加设置分区
  18. 主流图数据库对比,Neo4j、ArangoDB、OrientDB、JanusGraph、HugeGraph
  19. nslookup blog.csdn.net Can't resolve blog.csdn.net
  20. django 进阶第二天 生鲜超市学习 model

热门文章

  1. 【MySQL】rds 不支持镜像表/联合表,怎么办?
  2. Windows11 安装Docker,安装至D盘(其他非C盘皆可)
  3. springboot 远程调用shell脚本,环境为windows
  4. C#LeetCode刷题-深度优先搜索
  5. java开发工作经历_开发人员在寻找第二份工作时会经历什么
  6. python web应用_如何使用Python将通知发送到Web应用
  7. 所代币代币_代币网络效应
  8. 深入理解html5:语义,标准与样式pdf,深入理解html5语义标准与样式.doc
  9. boost库编译安装以及Qt导入
  10. python函数应用(1)