无论是初步跨入Linux殿堂的新手,仍是具备多年经验的专家,在安装或编译软件包的过程当中或多或少的都会遇到包的依赖问题,从而致使安装过程没法继续,好比管理员在安装LAMP时,包须要libgd.so文件,而这个文件属于GD软件包。可是在安装GD软件包时,可能这个软件包跟其余软件包又具备依赖关系,又须要安装其余软件包才行。这时有的管理员便失去耐心。在遇到这种Linux软件包依赖关系问题时,该如何解决呢?在谈这个具体的措施以前,先跟你们聊聊Linux系统里的软件依赖性问题。
1、什么是依赖性
程序依赖于程序代码的共享库,以便它们能够发出系统调用将输出发送到设备或打开文件等(共享库存在于许多方面,而不仅局限于系统调用)。没有共享库,每次程序员开发一个新的程序,每一个程序员都须要从头开始重写这些基本的系统操做。当编译程序时,程序员将他的代码连接到这些库。若是连接是静态的,编译后的共享库对象代码就添加到程序执行文件中;若是是动态的,编译后的共享库对象代码只在运行时须要它时由程序员加载。动态可执行文件依赖于正确的共享库或共享对象来进行操做。rpm依赖性尝试在安装时强制实施动态可执行文件的共享对象需求,以便在之后当程序运行时不会有与动态连接过程有关的任何问题。
注意:还有一种类型的依赖性,它基于显式的条目,rpm经过程序员将该依赖性强加到rpm配置文件中,但目前咱们不关心这种类型的依赖性,这种依赖性比较容易解决。这里将重点放在rpm强制实施的更加复杂的共享对象依赖性。
2、动态可执行文件和共享对象
动态可执行文件使用最初编译和连接程序时使用的库文件的共享对象名称来查找共享对象。它们在少数的几个标准位置查找,好比在/lib和/usr/lib目录及在LD_LIBRARY_PATH环境变量(主要用于指定查找共享库,好比咱们在安装Oracle时指定路径,export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib:/usr/local/lib)指定的目录中。顺便提一下,在这些库目录中找到的共享对象可能不是真正的文件;它们多是指向位于其余位置的真实库文件的符号连接(但一般仍旧在标准库目录的一个目录中)。至少从系统管理员的观点是在用于建立共享库文件的共享库软件包的名称和共享库文件的名称之间一般没有什么关系。例如,GLIBC 2.3软件包用于建立libc.so.6共享库文件。也从本示例中注意到,添加到共享库文件名结束的版本号(.6)跟用于建立它的版本号(2.3)没有关系。这是由共享库软件包开发人员有意完成的,以便GLIBC的新版本能够重用相同的共享库文件名libc.so.6。这容许您在系统上加载新版本的GLIBC,而不用中断动态连接到lib.so.6共享库文件的全部程序,固然假定新版本的GLIBC向后与动态可执行文件最初所连接的老版本GLIBC兼容。所以,即便库文件或共享对象文件有与它们相关的版本号,这些版本号也不能帮助你肯定他们来自哪一个版本的共享软件包。
注意:当将whatprovides选项用于rpm查询命令时,能够得到有关使用rpm软件包加载到系统的现有共享对象的信息。这种混乱是由下面的事实形成的:单个共享库文件可能支持某个范围的共享库软件包版本。例如,要检查soname库文件/lib/libc.so.6支持的GLIBC共享库软件包,运行下面的命令:
#objdump --all-headers /lib/libc.so.6 | less
向下滚动此报告,直到到达Version definitions: 部分,以便查看libc.so.6共享库文件支持哪些GLIBC版本:
Version definitions:
1 0x01 0x0865f4e6 libc.so.6
2 0x00 0x0d696910 GLIBC_2.0
3 0x00 0x0d696911 GLIBC_2.1
GLIBC_2.0
4 0x00 0x09691f71 GLIBC_2.1.1
GLIBC_2.1
5 0x00 0x09691f72 GLIBC_2.1.2
GLIBC_2.1.1
6 0x00 0x09691f73 GLIBC_2.1.3
GLIBC_2.1.2
7 0x00 0x0d696912 GLIBC_2.2
GLIBC_2.1.3
8 0x00 0x09691a71 GLIBC_2.2.1
GLIBC_2.2
9 0x00 0x09691a72 GLIBC_2.2.2
GLIBC_2.2.1
10 0x00 0x09691a73 GLIBC_2.2.3
GLIBC_2.2.2
11 0x00 0x09691a74 GLIBC_2.2.4
GLIBC_2.2.3
12 0x00 0x09691a76 GLIBC_2.2.6
GLIBC_2.2.4
13 0x00 0x0d696913 GLIBC_2.3
GLIBC_2.2.6
14 0x00 0x09691972 GLIBC_2.3.2
GLIBC_2.3
15 0x00 0x09691973 GLIBC_2.3.3
GLIBC_2.3.2
16 0x00 0x09691974 GLIBC_2.3.4
GLIBC_2.3.3
17 0x00 0x0d696914 GLIBC_2.4
GLIBC_2.3.4
18 0x00 0x0d696915 GLIBC_2.5
GLIBC_2.4
19 0x00 0x0963cf85 GLIBC_PRIVATE
GLIBC_2.5
20 0x00 0x0b792650 GCC_3.0
在本示例中,1ibc.so.6共享库文件支持原先为GLIBC版本2.0到2.5而开发的全部动态执行文件。注意:也可使用objdump命令来从共享库文件中提取soname,命令以下所示:
# objdump --all -headers /lib/libcrypto.so.0.9.8b| grep SONAME
SONAME libcrypto.so.6
objdump: /lib/libcrypto.so.0.9.8b: no recognized debugging information
接下来,将讨论rpm软件包是如何生成的,以便在新系统上安装rpm软件包时,这些共库依赖性是己知的。
3、Rpm软件包和共享库依赖性
当程序员生成rpm软件包时,ldd命令用于报告动态可执行文件软件包中全部动态可执行文件使用的全部共享库。另外一个混乱是由下面的事实带来的:相同软件包中的不一样动态可执行文件可能与相同的共享库软件包的不一样版本进行连接。例如,Heartbeat软件包中的不一样程序可能已经进行了开发,并动态连接到libc.so.6 sonmae共享库文件的不一样GLIBC版本。对rpm命令使用-q和--requires参数,能够看到rpm软件包须要的共享库的完整清单。例如,要看到Heartbeat rpm软件包全部的所需依赖性,请使用命令:
#rpm -q --requires -p heartbeat-1.x.x.i386.rpm
这产生了下面的报告:
sysklogd
/bin/sh
/bin/sh
/usr/bin/python
ld-linux.so.2
libapphb.so.0
libc.so.6
libc.so.6(GLIBC_2.0)
libc.so.6(GLIBC_2.1)
libc.so.6(GLIBC_2.1.3)
libc.so.6(GLIBC_2.2)
libc.so.6(GLIBC_2.3)
libccmclient.so.0
libdl.so.2
libglib-1.2.so.0
libhbclient.so.0
libpils.so.0
libplumb.so.0
libpthread.so.0
librt.so.1
libstonith.so.0
注意,在此报告中,libc.so.6 soname是所须要的,此共享库必须支持使用GLIBC共享软件包版本号2.0、2.一、2.1.三、2.2和2.3进行连接的动态可执行文件。这是由下面的事实决定的:Heartbeat软件包中的不一样动态可执行文件是针对不一样版本的libc.so.6库的每一个版本进行连接的。在了解了动态可执行文件、共享对象、soname和共享库软件包彼此是如何相关的后,下面准备来看这样的一个例子:当尝试安装rpm软件包,而且它因为依赖性错误而失败时,会发生什么。yum可以从指定的服务器自动下载RPM包而且安装,能够自动处理依赖性关系,而且一次安装全部依赖的软体包,无须繁琐地一次次下载、安装。
4、手工解决依赖性问题
一般,当尝试安装发行版中没有包括的软件包(及不能由像up2date、apt- get或Yum同样的更新工具自动解决其依赖性的软件包)时,将碰到rpm依赖性错误。例如,若是尝试在老的Linux发行版上使用rpm –ivh *rpm命令,例如全部的Heartbeat rpm包,那么在安装过程当中就可能碰到下面的错误:
error: failed dependencies:
libc.so.6(GLIBC_2.3) is needed by heartbeat-1.x.x
libc.so.6(GLIBC_2.3) is needed by heartbeat-pils-1.x.x
libcrypto.so.0.9.6 is needed by heartbeat-stonith-1.x.x
libsnmp-0.4.2.6.so is needed by heartbeat-stonith-1.x.x
注意,rpm命令没有干扰报告所需的每一个GLIBC共享库软件包版本号——它只报告所需的最高编号的版本号(GLIBC_2.3)。(假定原来的软件包开发人员不会将相同软件包中的可执行文件连接到不兼容版本的共享库软件包)全部的这些故障都报告所需的共享库名称或soname(而不是文件名称,soname始终以“lib”开始)。但能够删除添加到rpm报告的soname结束的版本号,并快速检查以查看是否在系统中使用locate命令安装这些共享库(假设您的locate数据库是最新的,有关更多信息,请参阅locate或slocate的手册页)。例如,要查找libcrypto享库文件,要输入:
#locate libcrypto
[root@localhost ~]# locate libcrypto
/lib/libcrypto.so.0.9.8b
/lib/libcrypto.so.6
/root/.Trash/vmware-tools-distrib/lib/lib32/libcrypto.so.0.9.8
/root/.Trash/vmware-tools-distrib/lib/lib32/libcrypto.so.0.9.8/libcrypto.so.0.9.8
/root/.Trash/vmware-tools-distrib/lib/lib64/libcrypto.so.0.9.8
/root/.Trash/vmware-tools-distrib/lib/lib64/libcrypto.so.0.9.8/libcrypto.so.0.9.8
/usr/lib/libcrypto.a
/usr/lib/libcrypto.so
/usr/lib/pkgconfig/libcrypto.pc
/usr/lib/vmware-tools/lib32/libcrypto.so.0.9.8
/usr/lib/vmware-tools/lib32/libcrypto.so.0.9.8/libcrypto.so.0.9.8
/usr/lib/vmware-tools/lib64/libcrypto.so.0.9.8
/usr/lib/vmware-tools/lib64/libcrypto.so.0.9.8/libcrypto.so.0.9.8
若是此命令没有在系统上找到一个libcrypto共享库文件,将须要转到Internet并找出哪一个共享库软件包包含此共享库文件。完成此项工具的一个快速和简便方式是只要在http://rpmfind.net上将共享库的名称输入到搜索栏中。若是将文本libcrypto.so输入到此搜索贞中,将很快知道此共享库是由openssl软件包提供的。
若是老版本的共享库数据包已经安装在系统上,能够用以下的命令确认此软件包含您须要的共享库文件:
#rpm -q --provides openssl
[root@localhost ~]# rpm -q --provides openssl
config(openssl) = 0.9.8b-10.el5
lib4758cca.so
libaep.so
libatalla.so
libchil.so
libcrypto.so.6
libcswift.so
libgmp.so
libnuron.so
libssl.so.6
libsureware.so
libubsec.so
openssl = 0.9.8b-10.el5
此命令报告此rpm软件包中提供的全部内容(这包括软件包提供的共享库文件的soname)。注意:如前面指出的,共享库软件包版本号没有而且应该没有与共享库文件( soname)版本号的任何对应关系。这里不进行这方面的讨论,由于soname符号连接可能指向不一样版本的共享库文件,这也是在尽可能避免在安装新版本的共享软件包时中断现有动态可执行文件的状况下完成的。
5、自动解决依赖性故障
当您使用rpm软件包来生成、升级或添加新的特性到系统时,依赖性故障可能很快变成一场恶梦。只要经过使用您的发行版供应商的升级服务或工具,就能够避免这场恶梦。例如,当选择要安装的rpm软件包时,Red Hat工具up2date自动从Red Hat下载并安装全部rpm依赖性。下面就点上列出了几个完成相同事情的支持社区的免费方法:http://www.rpm.org/。下面将只进一步看到这些自动更新工具中的一种:Yum。
1.使用Yum来安装rpm软件包
Yum(Yellow dog Updater,Modified)程序可从下面网址下载:http://yum.baseurl.org/download/3.4/yum-3.4.3.tar.gz
在下载了此软件包后,可使用下面的命令像任何其余rpm软件包那样安装它:
#rpm -ivh yum*
您可能须要更新想用于下载您的rpm软件包的存储库。有关Fedora的可用Yum存储库的清单在http://www.fedoratracker.org要切换到不一样的存储库,下载这些文件中的一个文件,并将该文件做为/etc/yum.conf文件安装。如今能够用下面的命令告诉Yum报告存储在Yum存储库中、可用于安装全部软件包:
#yum list
[root@localhost ~]# yum list |more
This system is not registered with RHN.
RHN support will be disabled.
Loading "security" plugin
Loading "rhnplugin" plugin
Installed Packages
Deployment_Guide-en-US.noarch 5.2-9 installed
Deployment_Guide-zh-CN.noarch 5.2-9 installed
Deployment_Guide-zh-TW.noarch 5.2-9 installed
GConf2.i386 2.14.0-9.el5 installed
GConf2-devel.i386 2.14.0-9.el5 installed
ImageMagick.i386 6.2.8.0-4.el5_1.1 installed
MAKEDEV.i386 3.23-1.2 installed
MySQL-python.i386 1.2.1-1 installed
NetworkManager.i386 1:0.6.4-8.el5 installed
NetworkManager-glib.i386 1:0.6.4-8.el5 installed
2.用Yum安装新的rpm软件包
在本示例中,将安装新的GLIBC软件包。用简单的命令安装最新的GLIBC及其全部依赖性:
#yum update glibc
若是一切正常,Yum程序将自动检测、下载并安装最新GLIBC软件包所须要的全部rpm软件包(这里的GLIBC软件包是为您的发行版而构建的,不必定是可用的最新版GLIBC软件包(使用发行版所批准的GLIBC共享库软件包版本号或冒险安装没有使用正常系统操做所须要的动态可执行文件的GLIBC软件包版本)。也能够将list参数用于Yum和grep命令来查找要安装的软件包。例如,要查找名称中有SNMP的软件包,请输入:
# yum list |grep snmp
此命令返回以下报告:
This system is not registered with RHN.
RHN support will be disabled.
net-snmp.i386 1:5.3.1-24.el5 installed
net-snmp-libs.i386 1:5.3.1-24.el5 installed
net-snmp-perl.i386 1:5.3.1-24.el5 installed
net-snmp-utils.i386 1:5.3.1-24.el5 installed
如今能够容易地使用YUM下载并安装全部这些rpm软件包。
6、关于升级Gilbc的建议
Glibc 库是Linux 底层的运行库,其性能对于整个系统的运行有重要的意义。Glibc 库包含了大量函数,其中的函数可大体分红两类,一类是与操做系统核心沟通的系统调用接口,它们做为功能型函数被调用,提供对Linux 操做系统调用的包装与预处理。另一类为通常的函数对象,它们提供了常用的功能的实现,做为工具型函数使用。在实践中,有很多软件就是依赖与Glibc版本才能安装并运行,说白了对于Glibc版本要求是版本高了不行,低了还不成。这些编译环境中的应用程序也和其它程序同样必须有运行的环境,我常遇到管理员在生产中给服务器装了最新的Linux发行版,结果应用软件装不上去,缘由是Glibc的版本不对,有的是写在原发行版glibc上升级有的是降级,结果却是整个系统的崩溃,实践经验告诉我,你只有选择相应Linux发行版里对应的glibc,例如咱们单位的一个应用软件时在rhel3.0下开发的,那么就得要对应的发行版,换了别的就难说了,任何本身升级或降级Glibc来适应应用软件的作法都是不可取的,问题最后的解决方法是找到了RHEL3装上就解决了。在表一中,我把几个linux发行版原配的Glibc版本列出,供你们参考。
点击图片查看大图
Glibc库与核心功能组件
上图一说明:
GCC依赖于glibc
binutils依赖于glibc (binutils提供了一系列用来建立、管理和维护二进制目标文件的工具程序,如汇编(as)、链接(ld)、静态库归档(ar)、反汇编)
make依赖于glibc
头文件是在编译时候gcc所须要的,但自己都是一些文本文件,所以没有须要的运行环境。
经常使用工具依赖于glibc和各类须要用到的动态库。
下表一列出了多个重要Linux发行版的Glibc的状况
Linux发行版 Glibc版本
Redhat 9 glibc-2.3.2-5
Fedora 1 glibc-2.3.2
Redhat Enterprise Linux As 3 glibc-2.3.2-95
Redhat Enterprise Linux As 4 glibc-2.3.4
Red hat Enterprise linux 5 glibc-2.5-24
Red hat Enterprise linux 6 glibc-2.9
Centos 5.x glibc-2.5
Suse Linux Enterprise Server 9 glibc-2.3.2-92
Suse Linux enterprise Server 10 glibc-2.4.31.54
Suse Linux Enterprise Server 11 glibc-2.9
点击图片查看大图
Linux发行版glibc (32)位
下面介绍几个查询glibc版本号的方法 :
#ls –al /lib/libc*
或者是用下面的命令也能够实现
#rpm –qp |grep glibc
基于debian的系统经过dpkg –l | grep libc6也能够查到,总之通常都在/usr/share/doc目录下都能看到glibc的相关信息。
七 、小结
大部分状况下,在遇到软件包依赖关系问题的时候,操做系统提供的文件名字与软件包名字都会有直接的联系。有可能文件的名字就是软件包的名字。可是有些时候文件的名字与软件包的名字会相差甚远。此时大部分系统管理员可能光凭文件名字没法找到对应的软件包。此时能够先在系统安装光盘里找,若是找到那时最佳选项,而后就须要借助笔者上面谈到的一些专业网站,去查询软件包的名字了。当系统管理员安装了某个软件以后,若是存在软件包之间的依赖关系,则最好可以拿本子或者经过其余手段记录下来。以便下次方便实用,注意工做中的积累,相信绝大部分的软件包依赖关系问题都会迎刃而解。
本文出自 “李晨光原创技术博客” 博客,请务必保留此出处http://chenguang.blog.51cto.com/350944/1034095python