Linux命令——ldd和ldconfig

时间:2021-11-17 10:56:50

转自:Linux系统中“动态库”和“静态库”那点事儿

前言

在调试lua脚本的时候,报错。

Linux命令——ldd和ldconfig

我已经再lua脚本中更改了cpath

package.cpath = package.cpath .. ";/usr/local/lib/?.so"

而且在/usr/local/lib有liblualongnumber.so.0啊,怎么会找不到呢?

Linux命令——ldd和ldconfig

下文将介绍此问题的解决过程

理论部分

参考:

剖析可执行文件ELF组成

剖析.o文件ELF组成

目标文件

.symtab

编译

剖析gcc -v输出

静态库 VS 动态库

静态链接 VS 动态链接

Linux系统中“动态库”和“静态库”那点事儿

从源代码到进程

Linux命令——ldd和ldconfig

静态链接(Static Linking)

Linux命令——ldd和ldconfig

动态链接/动态加载

Linux命令——ldd和ldconfig

库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。

静态库

这类库的名字一般是libxxx.a,xxx为库的名字。利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

动态库

这类库的名字一般是libxxx.M.N.so,同样的xxx为库的名字,M是库的主版本号,N是库的副版本号。当然也可以不要版本号,但名字必须有。相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。

当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

有时候当我们的应用程序无法运行时,它会提示我们说它找不到什么样的库,或者哪个库的版本又不对等等之类的问题。那么应用程序它是怎么知道需要哪些库的呢?ldd命令(下文有介绍)就可以查看动态文件(可执行文件,动态库)依赖了那些文件。

Linux系统中动态链接库的配置文件一般在/etc/ld.so.conf文件内。这个文件内容比较有意思

include /etc/ld.so.conf.d/*.conf

他指向/etc/ld.so.conf.d/目录下所有conf文件。这些文件有志向了具体目录,那些目录下面就是Linux系统要找的共享对象。

root@ubuntu:/etc/ld.so.conf.d# ls
fakeroot-x86_64-linux-gnu.conf libc.conf x86_64-linux-gnu.conf
root@ubuntu:/etc/ld.so.conf.d# cat *
/usr/lib/x86_64-linux-gnu/libfakeroot
# libc default configuration
/usr/local/lib
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
root@ubuntu:/etc/ld.so.conf.d# ls -m /lib/x86_64-linux-gnu
device-mapper, ld-2.23.so, ld-linux-x86-.so., libacl.so., libacl.so.1.1., libaio.so., libaio.so.1.0., libanl-2.23.so,
libanl.so., libapparmor.so., libapparmor.so.1.4., libatm.so., libatm.so.1.0., libattr.so., libattr.so.1.1., libaudit.so.,
libaudit.so.1.0., libblkid.so., libblkid.so.1.1., libBrokenLocale-2.23.so, libBrokenLocale.so., libbsd.so., libbsd.so.0.8.,
libbz2.so., libbz2.so.1.0, libbz2.so.1.0., libc-2.23.so, libcap.so., libcap.so.2.24, libcidn-2.23.so, libcidn.so., libcom_err.so.,
libcom_err.so.2.1, libcrypt-2.23.so, libcrypto.so.1.0., libcryptsetup.so., libcryptsetup.so.4.6., libcrypt.so., libc.so.,
libdbus-.so., libdbus-.so.3.14., libdevmapper-event-lvm2mirror.so, libdevmapper-event-lvm2raid.so,
libdevmapper-event-lvm2snapshot.so, libdevmapper-event-lvm2.so.2.02, libdevmapper-event-lvm2thin.so, libdevmapper-event.so.1.02.,
libdevmapper.so.1.02., libdl-2.23.so, libdl.so., libdns-export.so., libdns-export.so.162.1., libe2p.so., libe2p.so.2.3,
libexpat.so., libexpat.so.1.6., libext2fs.so., libext2fs.so.2.4, libfdisk.so., libfdisk.so.1.1., libfuse.so., libfuse.so.2.9.,
libgcc_s.so., libgcrypt.so., libgcrypt.so.20.0., libglib-2.0.so., libglib-2.0.so.0.4800., libgpg-error.so.,
libgpg-error.so.0.17., libhistory.so., libhistory.so.5.2, libhistory.so., libhistory.so.6.3, libip4tc.so., libip4tc.so.0.1.,
libip6tc.so., libip6tc.so.0.1., libiptc.so., libiptc.so.0.0., libisc-export.so., libisc-export.so.160.0., libjson-c.so.,
libjson-c.so.2.0., libkeyutils.so., libkeyutils.so.1.5, libkmod.so., libkmod.so.2.3., liblvm2app.so.2.2, liblvm2cmd.so.2.02,
liblzma.so., liblzma.so.5.0., liblzo2.so., liblzo2.so.2.0., libm-2.23.so, libmemusage.so, libmnl.so., libmnl.so.0.1.,
libmount.so., libmount.so.1.1., libm.so., libmvec-2.23.so, libmvec.so., libncurses.so., libncurses.so.5.9, libncursesw.so.,
libncursesw.so.5.9, libnewt.so.0.52, libnewt.so.0.52., libnih.so., libnih.so.1.0., libnl-.so., libnl-.so.200.22.,
libnl-genl-.so., libnl-genl-.so.200.22., libnsl-2.23.so, libnsl.so., libnss_compat-2.23.so, libnss_compat.so.,
libnss_dns-2.23.so, libnss_dns.so., libnss_files-2.23.so, libnss_files.so., libnss_hesiod-2.23.so, libnss_hesiod.so.,
libnss_nis-2.23.so, libnss_nisplus-2.23.so, libnss_nisplus.so., libnss_nis.so., libntfs-3g.so., libntfs-3g.so.861.0.,
libpamc.so., libpamc.so.0.82., libpam_misc.so., libpam_misc.so.0.82., libpam.so., libpam.so.0.83., libparted.so.,
libparted.so.2.0., libpci.so., libpci.so.3.3., libpcprofile.so, libpcre.so., libpcre.so.3.13., libply-boot-client.so.,
libply-boot-client.so.4.0., libply.so., libply.so.4.0., libply-splash-core.so., libply-splash-core.so.4.0.,
libply-splash-graphics.so., libply-splash-graphics.so.4.0., libpng12.so., libpng12.so.0.54., libpopt.so., libpopt.so.0.0.,
libprocps.so., libprocps.so.4.0., libpthread-2.23.so, libpthread.so., libreadline.so., libreadline.so.5.2, libreadline.so.,
libreadline.so.6.3, libresolv-2.23.so, libresolv.so., librt-2.23.so, librt.so., libseccomp.so., libseccomp.so.2.2., libSegFault.so,
libselinux.so., libsepol.so., libslang.so., libslang.so.2.3., libsmartcols.so., libsmartcols.so.1.1., libssl.so.1.0.,
libss.so., libss.so.2.0, libsystemd.so., libsystemd.so.0.14., libthread_db-1.0.so, libthread_db.so., libtinfo.so.,
libtinfo.so.5.9, libudev.so., libudev.so.1.6., libulockmgr.so., libulockmgr.so.1.0., libusb-0.1.so., libusb-0.1.so.4.4.,
libusb-1.0.so., libusb-1.0.so.0.1., libutil-2.23.so, libutil.so., libuuid.so., libuuid.so.1.3., libwrap.so., libwrap.so.0.7.,
libxtables.so., libxtables.so.11.0., libz.so., libz.so.1.2., security

细心的你可能会发现,在/etc目录下还存在一个名叫ld.so.cache的文件。从名字来看,估计和动态链接库缓存有关。的确,为了使得动态链接库可以被系统使用,当我们修改了/etc/ld.so.conf或/etc/ld.so.conf.d/目录下的任何文件,或者往那些目录下拷贝了新的动态链接库文件时,都需要运行一个很重要的命令:ldconfig,该命令位于/sbin目录下,主要的用途就是负责搜索/lib和/usr/lib,以及配置文件/etc/ld.so.conf里所列的目录下搜索可用的动态链接库文件,然后创建出动态加载程序/lib/ld-linux.so.2所需要的链接和(默认)缓存文件/etc/ld.so.cache(此文件里保存着已经排好序的动态链接库名字列表)。

也就是说:当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig目录名"这个命令。此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,即:在缓存文件/etc/ld.so.cache中追加进指定目录下的共享库。请注意:如果此目录不在/lib,/usr/lib及/etc/ld.so.conf文件所列的目录里面,则再次单独运行ldconfig时,此目录下的动态链接库可能不被系统共享了。单独运行ldconfig时,它只会搜索/lib、/usr/lib以及在/etc/ld.so.conf文件里所列的目录,用它们来重建/etc/ld.so.cache。

因此,对于我们自己开发的共享库可以将其拷贝到/lib、/etc/lib目录里,或者修改/etc/ld.so.conf文件将我们自己的库路径添加到该文件中,再执行ldconfig命令。

动态库使用参考:Linux下动态库的制作与使用

ldd(List Dynamic Dependencies)

功能

列出可执行文件或共享库的依赖文件,这里的依赖指的是动态库

语法

ldd(选项)(参数)
选项

--version:打印指令版本号;
-v:Print all information, including, for example, symbol versioning information.

[root@localhost lib]# ldd -v  /usr/bin/ls
linux-vdso.so. => (0x00007ffc28747000)
libselinux.so. => /lib64/libselinux.so. (0x00007fa1d1a37000)
libcap.so. => /lib64/libcap.so. (0x00007fa1d1832000)
libacl.so. => /lib64/libacl.so. (0x00007fa1d1629000)
libc.so. => /lib64/libc.so. (0x00007fa1d125c000)
libpcre.so. => /lib64/libpcre.so. (0x00007fa1d0ffa000)
libdl.so. => /lib64/libdl.so. (0x00007fa1d0df6000)
/lib64/ld-linux-x86-.so. (0x00007fa1d1c5e000)
libattr.so. => /lib64/libattr.so. (0x00007fa1d0bf1000)
libpthread.so. => /lib64/libpthread.so. (0x00007fa1d09d5000) Version information:
/usr/bin/ls:
libacl.so. (ACL_1.) => /lib64/libacl.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.3.4) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
/lib64/libselinux.so.:
libdl.so. (GLIBC_2.2.5) => /lib64/libdl.so.
ld-linux-x86-.so. (GLIBC_2.) => /lib64/ld-linux-x86-.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
libc.so. (GLIBC_2.3.4) => /lib64/libc.so.
/lib64/libcap.so.:
libc.so. (GLIBC_2.3.4) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
libattr.so. (ATTR_1.) => /lib64/libattr.so.
/lib64/libacl.so.:
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.3.4) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
libattr.so. (ATTR_1.) => /lib64/libattr.so.
/lib64/libc.so.:
ld-linux-x86-.so. (GLIBC_2.) => /lib64/ld-linux-x86-.so.
ld-linux-x86-.so. (GLIBC_PRIVATE) => /lib64/ld-linux-x86-.so.
/lib64/libpcre.so.:
libpthread.so. (GLIBC_2.2.5) => /lib64/libpthread.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.3.4) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
/lib64/libdl.so.:
ld-linux-x86-.so. (GLIBC_PRIVATE) => /lib64/ld-linux-x86-.so.
libc.so. (GLIBC_PRIVATE) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
/lib64/libattr.so.:
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.
/lib64/libpthread.so.:
ld-linux-x86-.so. (GLIBC_2.2.5) => /lib64/ld-linux-x86-.so.
ld-linux-x86-.so. (GLIBC_2.) => /lib64/ld-linux-x86-.so.
ld-linux-x86-.so. (GLIBC_PRIVATE) => /lib64/ld-linux-x86-.so.
libc.so. (GLIBC_2.) => /lib64/libc.so.
libc.so. (GLIBC_2.3.2) => /lib64/libc.so.
libc.so. (GLIBC_PRIVATE) => /lib64/libc.so.
libc.so. (GLIBC_2.2.5) => /lib64/libc.so.

-u:Print unused direct dependencies.  (Since glibc 2.3.4.)

[root@localhost lib]# ldd -u  /usr/bin/ls
Unused direct dependencies:
/lib64/libselinux.so.
/lib64/libcap.so.
/lib64/libacl.so.

-d:Perform relocations and report any missing objects (ELF only).

[root@localhost lib]# ldd -d  /usr/bin/ls
linux-vdso.so. => (0x00007ffd88755000)
libselinux.so. => /lib64/libselinux.so. (0x00007f284ddcd000)
libcap.so. => /lib64/libcap.so. (0x00007f284dbc8000)
libacl.so. => /lib64/libacl.so. (0x00007f284d9bf000)
libc.so. => /lib64/libc.so. (0x00007f284d5f2000)
libpcre.so. => /lib64/libpcre.so. (0x00007f284d390000)
libdl.so. => /lib64/libdl.so. (0x00007f284d18c000)
/lib64/ld-linux-x86-.so. (0x00007f284dff4000)
libattr.so. => /lib64/libattr.so. (0x00007f284cf87000)
libpthread.so. => /lib64/libpthread.so. (0x00007f284cd6b000)

-r:Perform relocations for both data objects and functions, and report any missing objects or functions (ELF only).

[root@localhost lib]# ldd -r  /usr/bin/ls
linux-vdso.so. => (0x00007fff60bf9000)
libselinux.so. => /lib64/libselinux.so. (0x00007fd8560df000)
libcap.so. => /lib64/libcap.so. (0x00007fd855eda000)
libacl.so. => /lib64/libacl.so. (0x00007fd855cd1000)
libc.so. => /lib64/libc.so. (0x00007fd855904000)
libpcre.so. => /lib64/libpcre.so. (0x00007fd8556a2000)
libdl.so. => /lib64/libdl.so. (0x00007fd85549e000)
/lib64/ld-linux-x86-.so. (0x00007fd856306000)
libattr.so. => /lib64/libattr.so. (0x00007fd855299000)
libpthread.so. => /lib64/libpthread.so. (0x00007fd85507d000)

--help:显示帮助信息。

参数

文件:指定可执行程序或者文库。

使用

最简单粗暴的使用方式,不带任何参数

查看共享库的依赖文件

root@ubuntu:/usr/lib# file libevent_openssl.so
libevent_openssl.so: symbolic link to libevent_openssl-2.1.so.6.0.
root@ubuntu:/usr/lib# ldd libevent_openssl.so
linux-vdso.so. => (0x00007fffeb79d000)
libssl.so.1.0. => /lib/x86_64-linux-gnu/libssl.so.1.0. (0x00007f65cb531000)
libcrypto.so.1.0. => /lib/x86_64-linux-gnu/libcrypto.so.1.0. (0x00007f65cb0ed000)
libpthread.so. => /lib/x86_64-linux-gnu/libpthread.so. (0x00007f65caed0000)
libc.so. => /lib/x86_64-linux-gnu/libc.so. (0x00007f65cab05000)
libdl.so. => /lib/x86_64-linux-gnu/libdl.so. (0x00007f65ca901000)
/lib64/ld-linux-x86-.so. (0x000055a2680a3000)
root@ubuntu:/usr/lib# ldd libevent_openssl-2.1.so.6.0.
linux-vdso.so. => (0x00007ffe80873000)
libssl.so.1.0. => /lib/x86_64-linux-gnu/libssl.so.1.0. (0x00007f9e350a1000)
libcrypto.so.1.0. => /lib/x86_64-linux-gnu/libcrypto.so.1.0. (0x00007f9e34c5d000)
libpthread.so. => /lib/x86_64-linux-gnu/libpthread.so. (0x00007f9e34a40000)
libc.so. => /lib/x86_64-linux-gnu/libc.so. (0x00007f9e34675000)
libdl.so. => /lib/x86_64-linux-gnu/libdl.so. (0x00007f9e34471000)
/lib64/ld-linux-x86-.so. (0x000055d3f064b000)

查看可执行文件的依赖文件

root@ubuntu:/DNXY/projects/dnxy_bike/src# file brks
brks: ELF -bit LSB executable, x86-, version (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-.so., for GNU/Linux 2.6., BuildID[sha1]=9d70993a3c150c156164b1bd88927f27651987e5, not stripped
root@ubuntu:/DNXY/projects/dnxy_bike/src# ldd brks
linux-vdso.so. => (0x00007ffecf0d9000)
liblog4cpp.so. => ../third/lib/log4cpp/liblog4cpp.so. (0x00007fc23c150000)
libpthread.so. => /lib/x86_64-linux-gnu/libpthread.so. (0x00007fc23bf29000)
libjsoncpp.so => ../third/lib/log4cpp/libjsoncpp.so (0x00007fc23bcdf000)
libcurl.so. => ../third/lib/log4cpp/libcurl.so. (0x00007fc23ba7f000)
libthrift-0.11..so => /usr/local/lib/libthrift-0.11..so (0x00007fc23b7b8000)
libthriftnb-0.11..so => /usr/local/lib/libthriftnb-0.11..so (0x00007fc23b597000)
libevent-2.1.so. => ../third/lib/log4cpp/libevent-2.1.so. (0x00007fc23b341000)
libmysqlclient.so. => /usr/lib/x86_64-linux-gnu/libmysqlclient.so. (0x00007fc23ad30000)
libstdc++.so. => /usr/lib/x86_64-linux-gnu/libstdc++.so. (0x00007fc23a9ad000)
libm.so. => /lib/x86_64-linux-gnu/libm.so. (0x00007fc23a6a4000)
libgcc_s.so. => /lib/x86_64-linux-gnu/libgcc_s.so. (0x00007fc23a48e000)
libc.so. => /lib/x86_64-linux-gnu/libc.so. (0x00007fc23a0c3000)
/lib64/ld-linux-x86-.so. (0x000055f814b36000)
libz.so. => /lib/x86_64-linux-gnu/libz.so. (0x00007fc239ea9000)
libssl.so.1.0. => /lib/x86_64-linux-gnu/libssl.so.1.0. (0x00007fc239c40000)
libcrypto.so.1.0. => /lib/x86_64-linux-gnu/libcrypto.so.1.0. (0x00007fc2397fb000)
libdl.so. => /lib/x86_64-linux-gnu/libdl.so. (0x00007fc2395f7000)

不可以查看静态库的依赖文件

root@ubuntu:/usr/lib# ldd libcurl.a
not a dynamic executable

查看静态库的依赖文件(说依赖不太恰当,应该是包含)。参考:Linux命令——ar

root@ubuntu:/usr/lib# ar -t libcurl.a
libcurl_la-file.o
libcurl_la-timeval.o
libcurl_la-base64.o
libcurl_la-hostip.o
libcurl_la-progress.o
libcurl_la-formdata.o
libcurl_la-cookie.o
libcurl_la-http.o
libcurl_la-sendf.o
libcurl_la-ftp.o
libcurl_la-url.o
libcurl_la-dict.o
libcurl_la-if2ip.o
libcurl_la-speedcheck.o
libcurl_la-ldap.o
libcurl_la-version.o
libcurl_la-getenv.o
libcurl_la-escape.o
libcurl_la-mprintf.o
libcurl_la-telnet.o
libcurl_la-netrc.o
libcurl_la-getinfo.o
libcurl_la-transfer.o
libcurl_la-strcase.o
libcurl_la-easy.o
libcurl_la-security.o
libcurl_la-curl_fnmatch.o
libcurl_la-fileinfo.o
libcurl_la-ftplistparser.o
libcurl_la-wildcard.o
libcurl_la-krb5.o
libcurl_la-memdebug.o
libcurl_la-http_chunks.o
libcurl_la-strtok.o
libcurl_la-connect.o
libcurl_la-llist.o
libcurl_la-hash.o
libcurl_la-multi.o
libcurl_la-content_encoding.o
libcurl_la-share.o
libcurl_la-http_digest.o
libcurl_la-md4.o
libcurl_la-md5.o
libcurl_la-http_negotiate.o
libcurl_la-inet_pton.o
libcurl_la-strtoofft.o
libcurl_la-strerror.o
libcurl_la-amigaos.o
libcurl_la-hostasyn.o
libcurl_la-hostip4.o
libcurl_la-hostip6.o
libcurl_la-hostsyn.o
libcurl_la-inet_ntop.o
libcurl_la-parsedate.o
libcurl_la-select.o
libcurl_la-tftp.o
libcurl_la-splay.o
libcurl_la-strdup.o
libcurl_la-socks.o
libcurl_la-ssh.o
libcurl_la-ssh-libssh.o
libcurl_la-curl_addrinfo.o
libcurl_la-socks_gssapi.o
libcurl_la-socks_sspi.o
libcurl_la-curl_sspi.o
libcurl_la-slist.o
libcurl_la-nonblock.o
libcurl_la-curl_memrchr.o
libcurl_la-imap.o
libcurl_la-pop3.o
libcurl_la-smtp.o
libcurl_la-pingpong.o
libcurl_la-rtsp.o
libcurl_la-curl_threads.o
libcurl_la-warnless.o
libcurl_la-hmac.o
libcurl_la-curl_rtmp.o
libcurl_la-openldap.o
libcurl_la-curl_gethostname.o
libcurl_la-gopher.o
libcurl_la-idn_win32.o
libcurl_la-http_proxy.o
libcurl_la-non-ascii.o
libcurl_la-asyn-ares.o
libcurl_la-asyn-thread.o
libcurl_la-curl_gssapi.o
libcurl_la-http_ntlm.o
libcurl_la-curl_ntlm_wb.o
libcurl_la-curl_ntlm_core.o
libcurl_la-curl_sasl.o
libcurl_la-rand.o
libcurl_la-curl_multibyte.o
libcurl_la-hostcheck.o
libcurl_la-conncache.o
libcurl_la-pipeline.o
libcurl_la-dotdot.o
libcurl_la-x509asn1.o
libcurl_la-http2.o
libcurl_la-smb.o
libcurl_la-curl_endian.o
libcurl_la-curl_des.o
libcurl_la-system_win32.o
libcurl_la-mime.o
libcurl_la-sha256.o
libcurl_la-setopt.o
libcurl_la-curl_path.o
libcurl_la-curl_ctype.o
libcurl_la-curl_range.o
libcurl_la-psl.o
libcurl_la-vauth.o
libcurl_la-cleartext.o
libcurl_la-cram.o
libcurl_la-digest.o
libcurl_la-digest_sspi.o
libcurl_la-krb5_gssapi.o
libcurl_la-krb5_sspi.o
libcurl_la-ntlm.o
libcurl_la-ntlm_sspi.o
libcurl_la-oauth2.o
libcurl_la-spnego_gssapi.o
libcurl_la-spnego_sspi.o
libcurl_la-openssl.o
libcurl_la-gtls.o
libcurl_la-vtls.o
libcurl_la-nss.o
libcurl_la-polarssl.o
libcurl_la-polarssl_threadlock.o
libcurl_la-axtls.o
libcurl_la-cyassl.o
libcurl_la-schannel.o
libcurl_la-schannel_verify.o
libcurl_la-darwinssl.o
libcurl_la-gskit.o
libcurl_la-mbedtls.o

在 ldd 命令打印的结果中,“=>”左边的表示该程序需要连接的共享库之 so 名称,右边表示由 Linux 系统找到的对应共享库在文件系统中的具体位置。默认情况下,/etc/ld.so.conf 文件中包含有默认的共享库搜索路径。

一个更好的替代

ldd本质上是一个脚本,并不是一个ELF格式的可执行文件。file使用

root@ubuntu:/# file /usr/bin/ldd
/usr/bin/ldd: Bourne-Again shell script, ASCII text executable

ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量,如下:LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、LD_VERBOSE等。当LD_TRACE_LOADED_OBJECTS环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的dependency,而程序并不真正执行。要不你可以在shell终端测试一下,如下:

export LD_TRACE_LOADED_OBJECTS=1

root@ubuntu:/usr/lib# export LD_TRACE_LOADED_OBJECTS=
root@ubuntu:/usr/lib# ls
linux-vdso.so. => (0x00007ffcd59fe000)
libselinux.so. => /lib/x86_64-linux-gnu/libselinux.so. (0x00007f775f7f6000)
libc.so. => /lib/x86_64-linux-gnu/libc.so. (0x00007f775f42c000)
libpcre.so. => /lib/x86_64-linux-gnu/libpcre.so. (0x00007f775f1bc000)
libdl.so. => /lib/x86_64-linux-gnu/libdl.so. (0x00007f775efb8000)
/lib64/ld-linux-x86-.so. (0x00007f775fa18000)
libpthread.so. => /lib/x86_64-linux-gnu/libpthread.so. (0x00007f775ed9b000)
root@ubuntu:/usr/lib# unset LD_TRACE_LOADED_OBJECTS
root@ubuntu:/usr/lib# ls
accountsservice libevent_openssl.so libopen-pal.so
apt libevent_pthreads-2.1.so. libopen-pal.so.
binfmt.d libevent_pthreads-2.1.so.6.0. libopen-pal.so.13.0.
byobu libevent_pthreads.a libopen-rte.so
command-not-found libevent_pthreads.la libopen-rte.so.
compat-ld libevent_pthreads.so libopen-rte.so.12.0.
dbus-1.0 libevent.so liboshmem.so
dpkg libguestlib.so. libtinyxml.a
dracut libguestlib.so.0.0. libvmtools.so.
eject libhgfs.so. libvmtools.so.0.0.
emacsen-common libhgfs.so.0.0. linux-boot-probes
gcc libibverbs.a locale
git-core libibverbs.so lxcfs
gnupg libibverbs.so. lxd
gold-ld libibverbs.so.1.0. man-db
groff libjsoncpp.a mime
grub libjsoncpp.so modules-load.d
grub-legacy libjson_linux-gcc-5.4.0_libmt.a mysql
initcpio libjson_linux-gcc-5.4.0_libmt.so openmpi
initramfs-tools liblog4cpp.a openssh
insserv liblog4cpp.la open-vm-tools
klibc liblog4cpp.so os-prober
language-selector liblog4cpp.so. os-probes
ldscripts liblog4cpp.so.5.0. os-release
libcurl.a libmca_common_sm.so perl5
libcurl.la libmca_common_sm.so. pkgconfig
libcurl.so libmca_common_sm.so.4.0. pkg-config.multiarch
libcurl.so. libmca_common_verbs.so pm-utils
libcurl.so.4.5. libmca_common_verbs.so. policykit-
libDeployPkg.so. libmca_common_verbs.so.7.0. python2.
libDeployPkg.so.0.0. libmpi_cxx.so python3
libevent-2.1.so. libmpi_cxx.so. python3.
libevent-2.1.so.6.0. libmpi_cxx.so.1.1. rsyslog
libevent.a libmpi_mpifh.so sasl2
libevent_core-2.1.so. libmpi_mpifh.so. scons
libevent_core-2.1.so.6.0. libmpi_mpifh.so.12.0. sftp-server
libevent_core.a libmpi.so snapd
libevent_core.la libmpi++.so software-properties
libevent_core.so libmpi.so. ssl
libevent_extra-2.1.so. libmpi.so.12.0. sudo
libevent_extra-2.1.so.6.0. libmpi_usempif08.so systemd
libevent_extra.a libmpi_usempif08.so. tar
libevent_extra.la libmpi_usempif08.so.11.1. tasksel
libevent_extra.so libmpi_usempi_ignore_tkr.so tc
libevent.la libmpi_usempi_ignore_tkr.so. tmpfiles.d
libevent_openssl-2.1.so. libmpi_usempi_ignore_tkr.so.6.1. ubuntu-release-upgrader
libevent_openssl-2.1.so.6.0. libompitrace.so update-notifier
libevent_openssl.a libompitrace.so. valgrind
libevent_openssl.la libompitrace.so.0.0. x86_64-linux-gnu

ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld-linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。

实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2 --list program(这相当于ldd program)

某些环境下,某些ldd版本可能会试图执行ldd参数中对应的程序。因此对于那些不受信任的可执行文件或动态库请不要使用ldd,因为有更好的替代方案

objdump -p /path/to/program | grep NEEDED

root@ubuntu:/DNXY/projects/dnxy_bike/src# objdump -p brks | grep NEEDED
NEEDED liblog4cpp.so.
NEEDED libpthread.so.
NEEDED libjsoncpp.so
NEEDED libcurl.so.
NEEDED libthrift-0.11..so
NEEDED libthriftnb-0.11..so
NEEDED libevent-2.1.so.
NEEDED libmysqlclient.so.
NEEDED libstdc++.so.
NEEDED libm.so.
NEEDED libgcc_s.so.
NEEDED libc.so.
root@ubuntu:/DNXY/projects/dnxy_bike/src# ldd brks
linux-vdso.so. => (0x00007fff36d70000)
liblog4cpp.so. => ../third/lib/log4cpp/liblog4cpp.so. (0x00007ffb5bf49000)
libpthread.so. => /lib/x86_64-linux-gnu/libpthread.so. (0x00007ffb5bd22000)
libjsoncpp.so => ../third/lib/log4cpp/libjsoncpp.so (0x00007ffb5bad8000)
libcurl.so. => ../third/lib/log4cpp/libcurl.so. (0x00007ffb5b878000)
libthrift-0.11..so => /usr/local/lib/libthrift-0.11..so (0x00007ffb5b5b1000)
libthriftnb-0.11..so => /usr/local/lib/libthriftnb-0.11..so (0x00007ffb5b390000)
libevent-2.1.so. => ../third/lib/log4cpp/libevent-2.1.so. (0x00007ffb5b13a000)
libmysqlclient.so. => /usr/lib/x86_64-linux-gnu/libmysqlclient.so. (0x00007ffb5ab29000)
libstdc++.so. => /usr/lib/x86_64-linux-gnu/libstdc++.so. (0x00007ffb5a7a6000)
libm.so. => /lib/x86_64-linux-gnu/libm.so. (0x00007ffb5a49d000)
libgcc_s.so. => /lib/x86_64-linux-gnu/libgcc_s.so. (0x00007ffb5a287000)
libc.so. => /lib/x86_64-linux-gnu/libc.so. (0x00007ffb59ebc000)
/lib64/ld-linux-x86-.so. (0x0000559ef684b000)
libz.so. => /lib/x86_64-linux-gnu/libz.so. (0x00007ffb59ca2000)
libssl.so.1.0. => /lib/x86_64-linux-gnu/libssl.so.1.0. (0x00007ffb59a39000)
libcrypto.so.1.0. => /lib/x86_64-linux-gnu/libcrypto.so.1.0. (0x00007ffb595f4000)
libdl.so. => /lib/x86_64-linux-gnu/libdl.so. (0x00007ffb593f0000)

但是从输出结果看,objdump比ldd输出的依赖少了点。

ldconfig

功能

配置动态链接器运行时绑定(configure dynamic linker run-time bindings)

说明

对命令行指定的目录,文件/etc/ld.so.conf中指定的目录,/usr/lib和/lib等受新任的目录下面找到的最新共享库,ldconfig为他们创建必要的链接和缓存。链接和缓存给动态链接器ld.so使用。在确定哪些版本的链接应更新时,ldconfig会检查它遇到的库的头和文件名。 扫描库时,ldconfig忽略符号链接。

当任何库被连接的时候,ldconfig将尝试根据C库来推断ELF库的类型(eg:libc 5.x或libc 6.x(glibc))。因此在制作动态库时,明智的做法使用参数-lc显式连接到libc。 ldconfig能够将多个ABI类型的库存储单个缓存中,这些缓存允许本地运行多个ABI,如ia32 / ia64 / x86_64或sparc32 / sparc64。

现有的某些库没有包含足够的信息用于推导他们的类型,因此/etc/ld.so.conf文件格式允许指定期望的类型。但这仅限于对ELF类型,格式类似于“dirname = TYPE”,其中type可以是libc4,libc5或libc6。(此语法也适用于命令行)。不允许有空格。

包含=的目录名称不再合法,除非它们也具有预期的类型说明符。

通常情况下,ldconfig以root身份运行运行,因为它可能需要对某些目录和文件有root的写入权限。 如果使用-r选项更改根目录,只要您对该目录树有足够的权限,可以不必是root用户。

语法

ldconfig [OPTION...]

选项

-v --verbose

详细模式。在扫描动态库时,会显示动态库当前版本号,库在那个目录下,以及指向该库的链接。

root@ubuntu:~# ldconfig -v
...
/usr/lib/x86_64-linux-gnu/libfakeroot:
libfakeroot-.so -> libfakeroot-tcp.so
/usr/local/lib:
libluasocket.so. -> libluasocket.so.0.0.
libthrift-0.11..so -> libthrift.so
libthriftz-0.11..so -> libthriftz.so
libluabitwise.so. -> libluabitwise.so.0.0.
libthrift_c_glib.so. -> libthrift_c_glib.so.0.0.
liblua.so -> liblua.so
libthriftnb-0.11..so -> libthriftnb.so
libluabpack.so. -> libluabpack.so.0.0.
liblualongnumber.so. -> liblualongnumber.so.0.0.
...

->前面是后面的符号链接

-n

ldconfig仅扫描命令行指定下的目录,不扫描受信目录(/lib,/usr/lib)和配置文件/etc/ld.so.conf指定的目录。

-N

ldconfig不重建缓存文件(/etc/ld.so.cache),但是还会跟新文件的链接。除非指定-X

-X

ldconfig不更新文件的连接,但是还会重建缓存文件(/etc/ld.so.cache)。除非指定-N

-f conf

使用conf文件,而不是默认的/etc/ld.so.conf

-C cache

Use cache instead of /etc/ld.so.cache.

-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文件.用此选项,可以大大增加动态链接库管理的灵活性.

-l

通常情况下,ldconfig搜索动态链接库时将自动建立动态链接库的连接.选择此项时,将进入专家模式,需要手工设置连接.一般用户不用此项.

-p 或 --print-cache

此选项指示ldconfig打印出当前缓存文件所保存的所有共享库的名字。

-c FORMAT 或--format=FORMAT

此选项用于指定缓存文件所使用的格式,共有三种:ld(老格式),new(新格式)和compat(兼容格式,此为默认格式)。

-V 

此选项打印出ldconfig的版本信息,而后退出.

--help 或--usage 

这三个选项作用相同,都是让ldconfig打印出其帮助信息,而后退出。

ldconfig需要注意的地方

  1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf文件的,但是添加完后需要调用下ldconfig,不然添加的library会找不到。
  2. 如果添加的library不在/lib和/usr/lib里面的话,就一定要修改/etc/ld.so.conf文件,往该文件追加library所在的路径,然后也需要重新调用下ldconfig命令。比如在安装MySQL的时候,其库文件/usr/local/mysql/lib,就需要追加到/etc/ld.so.conf文件中。命令如下:

    # echo "/usr/local/mysql/lib" >> /etc/ld.so.conf

    # ldconfig -v | grep mysql

  3. 如果添加的library不在/lib或/usr/lib下,但是却没有权限操作写/etc/ld.so.conf文件的话,这时就需要往export里写一个全局变量LD_LIBRARY_PATH,就可以了。但是这种方法有个缺点,就是环境变量都是局部于进程的,也就是说你在一个shell终端export LD_LIBRARY_PATH,可以找到动态库。但是当shell终端关闭再打开的时候还是会报找不到动态库。这是和可以把export LD_LIBRARY_PATH写在.bashrc里面,这样只要一执行shell就能找到动态库。
  4. 除了export LD_LIBRARY_PATH方法外,把我们自己 写的动态库手动拷贝到/lib目录下也可以。/lib是系统动态链接库所在位置。一般不使用这种方法。

一个很好的中文在线man手册

Linux命令大全

最后说明最开始的那个问题是怎么解决的

Linux命令——ldd和ldconfig

其实就是执行了一遍ldconfig命令,命令虽简单,但是背后原理深刻,理解很重要。

Linux命令——ldd和ldconfig
Linux命令——ldd和ldconfig