`
longgangbai
  • 浏览: 7330165 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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)

 

分享到:
评论

相关推荐

    JNA-Linux下java程序调用so库接口函数

    在Linux系统下,JAVA程序通过JNA技术实现调用C语言编程输出的so库接口函数,从而实现java程序与c程序之间的交互。

    jna&jna-platform4.0版和5.6版本.zip

    JNA库本身包含了基本的映射功能,而`jna-platform`是JNA的一个扩展库,包含了大量常见操作系统的结构体、类型和函数映射,如Windows API、Unix/Linux系统调用等。这两个库结合使用,可以让Java开发者更方便地跨平台...

    jna.rar_jna_jna.jar_jna文件

    JNA通过动态链接库(DLLs on Windows,shared libraries on Unix/Linux)实现了这一点,极大地简化了Java应用程序与本地资源的交互。`jna.jar`文件是JNA库的核心组件,包含了所有必要的类和资源,使得开发者可以在...

    jna-platform-5.10.0-API文档-中英对照版.zip

    赠送jar包:jna-platform-5.10.0.jar; 赠送原API文档:jna-platform-5.10.0-javadoc.jar; 赠送源代码:jna-platform-5.10.0-sources.jar; 赠送Maven依赖信息文件:jna-platform-5.10.0.pom; 包含翻译后的API文档...

    jna-3.3.0 & jna-3.3.0-platform

    综上所述,`jna-3.3.0.jar`和`jna-3.3.0-platform.jar`是Java开发中调用本地资源的重要工具,它们提供了一种简便的方式让Java程序能够直接利用操作系统的能力,而无需深入学习C/C++编程。通过理解JNA的工作原理和...

    JNA 4.1.0 官方版

    JNA平台库提供了大量的结构体、枚举类型和函数接口,使得开发者能够方便地访问操作系统底层的服务,例如文件系统操作、进程管理、网络编程、图形界面交互等。通过这个库,开发者可以避免繁琐的JNI编码工作,直接在...

    jna整合包-jna4.5.0+jna4.0.0.rar

    在你提供的压缩包"jna整合包-jna4.5.0+jna4.0.0.rar"中,包含了两个版本的JNA库:jna-4.0.0.jar和jna-4.5.0.jar。这两个版本的差异主要体现在功能的完善和性能的优化上。JNA 4.5.0是较新的版本,相比4.0.0,它可能...

    JNA 使用方法

    3. 实现跨平台开发:JNA 可以用来实现跨平台开发,例如在 Windows 和 Linux 平台上开发相同的应用程序。 使用 JNA 需要: 1. 下载 JNA jar 包:...

    jna-4.2.2.jar jna-platform-4.2.2.jar

    标题中的"jna-4.2.2.jar"和"jna-platform-4.2.2.jar"是Java Native Access (JNA)框架的两个关键组件的版本号为4.2.2的JAR文件。JNA是Java平台上的一个开源库,它允许Java代码直接调用操作系统提供的原生函数,而无需...

    jna-3.0.9.jar和jna-examples.jar.zip

    import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.examples.win32.W32API.HWND; import com.sun.jna.ptr.ByteByReference; import ...

    支持loongarch64的jna-5.10.0.zip

    例如,如果需要调用Linux系统的`fork()`函数,只需在Java中定义一个带有适当参数和返回类型的`fork()`方法,JNA就能自动处理调用过程。 总的来说,"jna-5.10.0.zip"的发布,对于Loongarch64平台的Java开发者来说,...

    jna和examples.zip

    《JNA技术详解与实战应用》 ...通过学习和实践,我们可以利用JNA轻松地调用各种操作系统功能,实现诸如JFrame透明和不规则形状这样的高级特性。"examples"提供了丰富的实践案例,是进一步掌握JNA的宝贵资源。

    jna和examples的jar包

    `examples.jar` 包含的示例可能涵盖了上述功能的使用,帮助开发者理解如何利用 JNA 实现特定功能,例如在给定的场景下,JFrame 的透明和不规则形状的实现。 对于 JFrame 的透明度,JNA 可能被用来调用操作系统级别...

    JNA相关包 jna.jar

    而`jna-platform.jar`则包含了对常见操作系统API的预定义映射,例如Windows API、Unix和Linux的系统调用,以及Apple的CoreFoundation和Carbon框架等。 描述中的“JNA相关包”进一步确认了我们的焦点在于JNA的使用和...

    jna-3.0.9.jar和examples.jar

    标题中的"jna-3.0.9.jar和examples.jar"是两个重要的Java类库文件,它们在IT领域,特别是Java开发中具有显著的应用价值。JNA(Java Native Access)是一个开源项目,它提供了一种方便的方式来调用本地库(如C、C++...

    JNA_3.5.1_jar包和JNA—快速调用原生函数文档

    **platform-3.5.1.jar** 文件则是JNA的平台依赖部分,它包含了针对不同操作系统(如Windows、Linux、macOS等)的特定实现,确保在各种环境下都能正确地进行本地函数调用。例如,Windows上的动态链接库(.dll)和Unix...

    jna和jnaplatform5.5.rar

    JNA的核心在于它的`Platform`类,这个类提供了对不同操作系统平台的抽象,包括Windows、Linux、Mac OS X等。通过`com.sun.jna.platform.windows.WinDef`等包中的接口,Java程序员可以轻松地访问Windows API中的各种...

    android JNA 依赖jar 包

    - `platform.jar`:包含了各种平台特定的定义,如Windows、Linux、macOS等,使得JNA可以访问这些平台的API。 3. **使用JNA的步骤**: - 引入依赖:在Android项目中,需要将JNA和平台相关的jar包添加到项目的依赖...

    JNA实例 JNA实例 JNA实例

    ### JNA 实例详解 #### 一、JNA简介与应用场景 ...这种技术不仅简化了跨语言编程的过程,还提高了代码的可维护性和扩展性。对于需要与现有C/C++代码集成的项目来说,JNA提供了一个非常实用且高效的选择。

Global site tag (gtag.js) - Google Analytics