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

前言

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

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

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

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

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

理论部分

参考:

剖析可执行文件ELF组成

剖析.o文件ELF组成

目标文件

.symtab

编译

剖析gcc -v输出

静态库 VS 动态库

静态链接 VS 动态链接

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

从源代码到进程

静态链接(Static Linking)

动态链接/动态加载

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

静态库

这类库的名字一般是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命令大全

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

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

Linux命令——ldd和ldconfig的更多相关文章

  1. 【转】Linux动态链接(4)ldd与ldconfig

    原文网址:http://tsecer.blog.163.com/blog/static/15018172012414105551345/ 一.动态链接工具ldd和ldconfig是动态链接的两个重要辅 ...

  2. Linux下的库操作工具-nm、ar、ldd、ldconfig和ld.so

    Linux下的库操作工具-nm.ar.ldd.ldconfig和ld.so .nm [options] file 列出file中的所有符号 [option] -c 将符号转化为用户级的名字 -s 当用 ...

  3. 1· linux命令:查看依赖的共享库 - ldd命令

    今天使用qt链接mysql的时候,发现提示driver not load 而出现此错误一般是没有mysql驱动的原因,但是qt5.4已经提供了mysql驱动的 查看plugins/sqldrivers ...

  4. 最全的linux命令大全,shell运维手册

    shell实例手册 0 说明{ 手册制作: 雪松} 1 文件{        ls -rtl                 # 按时间倒叙列出所有目录和文件 ll -rt    touch file ...

  5. linux 命令中英文对照,收集

    linux 命令中英文对照,收集   linux 命令英文全文 Is Linux CLI case-sensitive? The answer is, yes. If you try to run L ...

  6. 《Linux命令学习手册》系列分享专栏

    <Linux命令学习手册>系列分享专栏 <Linux命令学习手册>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/207 ...

  7. 【转】linux命令

    shell实例手册 0 说明{ 手册制作: 雪松    更新日期: 2015-11-02 欢迎系统运维加入Q群: 198173206  # 加群请回答问题    欢迎运维开发加入Q群: 3655344 ...

  8. 我常用的那些linux命令

    我常用的那些linux命令 用linux也有些年头了,说来也忏愧,说是有些年头了,其实也还是个不长进的主.记得第一次接触linux是boss跟我说的怎么操作,什么编辑模式,按i,a,o进入编辑模式.在 ...

  9. LINUX命令总结 -------来自 水滴娃娃 的CSDN

    LINUX命令总结 标签: LINUX命令总结 2014-01-27 15:54 41039人阅读 评论(1) 收藏 举报  分类: linux(1)  版权声明:本文为博主原创文章,未经博主允许不得 ...

随机推荐

  1. sudo权限配置

    首先要禁止root的用户登录ssh  在ssh配置文件里面把root用户no掉,一般公司不允许用第三方软件直接root登陆. 一.linux给用户添加sudo权限: 有时候,linux下面运行sudo ...

  2. hdoj4099(字典树+高精度)

    题目链接:https://vjudge.net/problem/HDU-4099 题意:给T组询问,每个询问为一个字符串(长度<=40),求以该字符串为开始的fibonacci数列的第一个元素的 ...

  3. SpringMVC常用注解@Controller,@Service,@repository,@Component,@Autowired,@Resource,@RequestMapping

    1.controller层使用@Controller注解-用于呈现层,(spring-mvc) @Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controlle ...

  4. Quartz.Net—TriggerBuilder

    TriggerBuilder TriggerBuilder是一个建造者模式,链式建造.通过静态方法构建一个TriggerBuilder实例,然后再调用类方法Build()创建一个ITrigger的实现 ...

  5. oauth2 + jwt 实现用户中心

    由于公司项目比较杂,以前都是各产品线自行完成注册和登入.随着产品迭代,需要一个用户中心统一用户的管理,写个博客做个记录. 用oauth2实现,jwt作为token生成. oauth2流程图: user ...

  6. Java的设计模式(6)— 模板模式

    定义一个操作中算法的骨架,将一些步骤放在子类实现,使得子类可以不改变一个算法结构即子类可以重定义该算法的某些特定步骤. 主要有两个角色: 1. 抽象模板 :是一个抽象类,并实现了一个具体模板方法,这个 ...

  7. Linux基础-04-权限

    1. 查看文件的权限 1) 使用ls –l命令查看文件上所设定的权限. -rw-r--r-- 1 root root 605 Mar 18 20:28 .jp1.tar.gz 权限信息 属主 属组 文 ...

  8. 02 File类的方法练习——遍历文件夹

    思路 需要遍历的文件夹 File 使用listFile列出下级文件及文件夹 判断得到的list是否为空,为空则输出当前文件夹名称 如果不为空,逐个判断是文件还是文件夹 如果是文件,输出文件名 如果是文 ...

  9. ACM集训

    2019-07-18 09:06:10 emmm.... 昨天5个小时做了一道题,心情复杂,不着急慢慢来 Ivan recently bought a detective book. The book ...

  10. uwsgi flask gevent 测试代码覆盖率(coverage)

    目录 可能出现的问题 解决 可能出现的问题 多进程启动 gevent启动 运行的服务可能不会停止 解决 我先参考了一下这一篇文章使用Coverage分析WSGI项目的代码覆盖率,他基本能够解决掉1.2 ...