JNA编程之linux下ldconfig和ldd命令作用

linux下ldconfig命令作用

ldconfig是一个动态链接库管理命令

为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig
ldconfig 命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为 /etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.

ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.
ldconfig命令行用法如下:
ldconfig [-v|--verbose] [-n] [-N] [-X] [-f CONF] [-C CACHE] [-r ROOT] [-l] [-p|--print-cache] [-c FORMAT] [--format=FORMAT] [-V] [- |--help|--usage] path...
ldconfig可用的选项说明如下:
(1) -v或--verbose : 用此选项时,ldconfig将显示正在扫描的目录及搜索到的动态链接库,还有它所创建的连接的名字.
(2) -n : 用此选项时,ldconfig仅扫描命令行指定的目录,不扫描默认目录(/lib,/usr/lib),也不扫描配置文件/etc/ld.so.conf所列的目录.
(3) -N : 此选项指示ldconfig不重建缓存文件(/etc/ld.so.cache).若未用-X选项,ldconfig照常更新文件的连接.
(4) -X : 此选项指示ldconfig不更新文件的连接.若未用-N选项,则缓存文件正常更新.
(5) -f CONF : 此选项指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf.
(6) -C CACHE : 此选项指定生成的缓存文件为CACHE,系统默认的是/etc/ld.so.cache,此文件存放已排好序的可共享的动态链接库的列表.
(7) -r ROOT : 此选项改变应用程序的根目录为ROOT(是调用chroot函数实现的).选择此项时,系统默认的配置文件/etc/ld.so.conf,实际对应的为 ROOT/etc/ld.so.conf.如用-r /usr/zzz时,打开配置文件/etc/ld.so.conf时,实际打开的是/usr/zzz/etc/ld.so.conf文件.用此选项,可以大大增加动态链接库管理的灵活性.
(8) -l : 通常情况下,ldconfig搜索动态链接库时将自动建立动态链接库的连接.选择此项时,将进入专家模式,需要手工设置连接.一般用户不用此项.
(9) -p或--print-cache : 此选项指示ldconfig打印出当前缓存文件所保存的所有共享库的名字.
(10) -c FORMAT 或 --format=FORMAT : 此选项用于指定缓存文件所使用的格式,共有三种: ld(老格式),new(新格式)和compat(兼容格式,此为默认格式).
(11) -V : 此选项打印出ldconfig的版本信息,而后退出.
(12) - 或 --help 或 --usage : 这三个选项作用相同,都是让ldconfig打印出其帮助信息,而后退出.

linux命令:ldd

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。

 

linux下lib说明


一、lib类型:
与windows下静态库(.lib)和动态库(.dll)一样,linux同样存在静态库(static library 文件后缀为.a)和共享库(shared library 文件后缀为.so),在/usr/lib目录下同时存在一个库的静态版本和动态版本。

"An archive (or static library) is simply a collection of object files stored as a single file.
When you provide an archive to the linker, the linker searches the archive for the object files
it needs, extracts them, and links them into your program much as if you had provided those
object files directly."

"A shared library is similar to a archive in that it is a grouping of object files. However,
there are many important differences.The most fundamental difference is that when a shared library is
linked into a program, the final executable does not actually contain the code that is
present in the shared library. Instead, the executable merely contains a reference to the
shared library."
"the object files that compose the shared library are combined into a
single object file so that a program that links against a shared library always includes all
of the code in the library, rather than just those portions that are needed."
以上引自《Advanced Linux Programming》

由此可知,静态库和共享库都是一个obj文件的集合,但静态链接后,执行程序中存在自己所需obj的一份拷贝,而动态链接后,执行程序仅仅是包含对共享库的一个引用。共享库相当于一个由多个obj文件组合而成的obj文件,在链接后其所有代码被加载,不管需要的还是不需要的。
似乎可以得出一个结论:
静态链接后的程序比动态链接的所用存储空间大,因为执行程序中包含了库中代码拷贝;
而动态链接的程序比静态链接的所用的运行空间大,因为它将不需要的代码也加载到运行空间。

二、lib编译:
静态库的编译,实际上是一个将.o文件打包的过程。
ar -rc libfunc.a func1.o func2.o # 将f1.o、f2.o编译成静态库libfunc.a
动态库的编译,使用gcc -fPIC -shared编译选项。
gcc -fPIC -shared -o libfunc.so func1.o func2.o # 将f1.o、f2.o编译成动态库libfunc.so

三、lib调用:
静态库的调用比较简单,跟标准库函数调用一样
一个例子:main.c调用./lib目录下libfunc.a库,该库头文件在./inc目录下,编译:
gcc -o test main.c -I./inc -L./lib -lfunc

共享库的调用需要注意库文件放置位置,如果该库文件不在/lib、/usr/lib下,则需要设置LD_LIBRARY_PATH变量。
一个例子:main.c调用./lib目录下libfunc.so库,该库头文件在./inc目录下,如果使用编译:
gcc -o test main.c -I./inc -L./lib -lfunc
./test # 运行错误:error while loading shared libraries: libfunc.so
这是因为动态链接时程序只是存放共享库的名称而不是绝对路径,所以运行时我们需要先设置该库所处位置:
export LD_LIBRARY_PATH=./lib
./test # 运行成功

动态装载共享库:在只有共享库而没有库的头文件,或者你想在运行时动态加载、卸载库时,linux的dl库函数:dlopen、dlclose、dlsym帮你办到,其相当于windows下LoadLibrary、FreeLibrary、GetProcAddress函数函数原型:
void *dlopen(const char *filename, int flag);
void *dlsym(void *handle, char *symbol);
int dlclose(void *handle);
一个例子:main.c动态装载./lib目录下libfunc.so库,库中有一个函数void print_str(const char*);
/*加载库*/
void *handle = dlopen("libfunc.so", RTLD_LAZY);
/*获得函数的入口*/
void (*pt_str)(const char*);
pt_str = dlsym(handle, "print_str");
/*调用函数*/
pt_str("hello world.");
/*卸载库*/
dlclose(handle);

四、相关说明:
1、共享库特别适合多个程序共享代码,升级程序部分功能模块,实现程序“插件”功能的情况;而静态库是一劳永逸,编译后不需要带一堆库文件跑,而且不管放置到哪里都可正常运行。
2、当搜索的库文件目录下同时存在该库的静态版本和共享版本时,链接器优先使用共享版本.so,此时你可以使用-static链接选项指定链接静态版本.a。
3、动态库可以导出两个特殊的函数:_init和_fini,前者在动态库被加载后调用,后者在动态库被卸载前调用,我们可以使用这两个函数做些特别的工作。需要注意的是:在定义这两个函数后编译时,需要使用-nostartfiles选项,否则编译器报重复定义错误。
4、ldd命令用来查看程序所依赖的共享库,同时也方便我们判断共享库是否被找到;nm命令查看obj文件(.so也是一个obj)中的标识(函数、变量)。


更为详细的内容:
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)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值