Linux下的库文库.docx

上传人:b****4 文档编号:11679354 上传时间:2023-03-30 格式:DOCX 页数:14 大小:27.70KB
下载 相关 举报
Linux下的库文库.docx_第1页
第1页 / 共14页
Linux下的库文库.docx_第2页
第2页 / 共14页
Linux下的库文库.docx_第3页
第3页 / 共14页
Linux下的库文库.docx_第4页
第4页 / 共14页
Linux下的库文库.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

Linux下的库文库.docx

《Linux下的库文库.docx》由会员分享,可在线阅读,更多相关《Linux下的库文库.docx(14页珍藏版)》请在冰豆网上搜索。

Linux下的库文库.docx

Linux下的库文库

Linux下的库文库.txt“我羡慕内些老人羡慕他们手牵手一直走到最后。

━交话费的时候,才发现自己的话那么值钱。

一.库的分类

有两种说法,如果熟悉WIN平台下的DLL,相信不难理解:

库可以有三种使用的形式:

静态、共享和动态。

静态库的代码在编译时就已连接到开发人员开发的应用程序中,而共享库只是在程序开始运行时才载入,在编译时,只是简单地指定需要使用的库函数。

动态库则是共享库的另一种变化形式。

动态库也是在程序运行时载入,但与共享库不同的是,使用的库函数不是在程序运行开始,而是在程序中的语句需要使用该函数时才载入。

动态库可以在程序运行期间释放动态库所占用的内存,腾出空间供其它程序使用。

由于共享库和动态库并没有在程序中包括库函数的内容,只是包含了对库函数的引用,因此代码的规模比较小。

Linux下的库文件分为共享库和静态库两大类,它们两者的差别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。

区分库类型最好的方法是看它们的文件后缀,通常共享库以.so(SharedObject的缩写)结尾,静态链接库通常以.a结尾(Archive的缩写)。

在终端缺省情况下,共享库通常为绿色,而静态库为黑色。

 

已经开发的大多数库都采取共享库的方式。

ELF格式的可执行文件使得共享库能够比较容易地实现,当然使用旧的a.out模式也可以实现库的共享。

Linux系统中目前可执行文件的标准格式为ELF格式。

  .a的是为了支持较老的a.out格式的可执行文件的

  .so的是支持elf格式的可执行文件的库。

 .a是静态库文件,可以用ar命令生成。

  .so是动态库文件,编译时加上指定的选项即可生成,具体选项看相应的系统文档了。

 

二.库的命名规则

GNU库的使用必须遵守LibraryGNUPublicLicense(LGPL许可协议)。

该协议与GNU许可协议略有不同,开发人员可以免费使用GNU库进行软件开发,但必须保证向用户提供所用的库函数的源代码。

  系统中可用的库都存放在/usr/lib和/lib目录中。

库文件名由前缀lib和库名以及后缀组成。

根据库的类型不同,后缀名也不一样。

共享库的后缀名由.so和版本号组成,静态库的后缀名为.a。

采用旧的a.out格式的共享库的后缀名为.sa。

  libname.so.major.minor

  libname.a

  这里的name可以是任何字符串,用来唯一标识某个库。

该字符串可以是一个单字、几个字符、甚至一个字母。

数学共享库的库名为libm.so.5,这里的标识字符为m,版本号为5。

libm.a则是静态数学库。

X-Windows库名为libX11.so.6,这里使用X11作为库的标识,版本号为6。

三。

库操作命令

Linux库操作可以使用命令完成,目前常用的命令是ldd和ldconfig。

1.ldd

ldd是LibraryDependencyDisplay缩写,它的作用是显示一个可执行程序必须使用的共享库。

$ldd/usr/bin/mesg

libc.so.6=>/lib/tls/i686/cmov/libc.so.6(0xb7eaf000)

/lib/ld-linux.so.2=>/lib/ld-linux.so.2(0xb7feb000)

2.ldconfig

库安装到系统以后,为了让动态链接库为系统所认识及共享,就需要运行ldconfig。

ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件。

缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表,ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令。

(1)命令格式

ldconfig[选项][libs]

(2)主要选项

-v或--verboseldconfig将显示正在扫描的目录、搜索到的动态链接库,以及它所创建的连接的名字。

-fCONF指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf。

-CCACHE指定生成的缓存文件为CACHE,系统默认的是/etc/ld.so.cache,文件存放已排好序的可共享的动态链接库的列表。

-p或--print-cache让ldconfig打印出当前缓存文件所保存的所有共享库的名字。

-rROOT改变应用程序的根目录为ROOT。

-nldconfig仅扫描命令行指定的目录,不扫描默认目录(/lib、/usr/lib),也不扫描配置文件/etc/ld.so.conf所列的目录。

运行没有选项的ldconfig命令时,用于更新高速缓冲文件。

这个命令主要用于高速缓冲DNS服务器(CachingDNSServer)。

高速缓冲DNS服务器的原理是提供查询的历史记录,并且利用这些记录来提高查询的效率。

当某个查询是第一次被发送到高速缓冲DNS服务器时,高速缓冲DNS服务器就将此查询的整个过程记录下来,在一定的时期内用它来回答所有相同的查询,从而减少整个DNS系统的负担并且提高查询速度。

四。

库的升级

Linux系统软件更新很快,新的核心几乎每几个星期就公布一次,其它软件的更新也是非常频繁。

多数情况下,盲目跟随潮流的升级并不必要,如果确实需要新版本的特性时再升级。

换句话说,不要为了升级而升级。

Linux系统中多数软件都是用共享库来编译的,其中包含了在不同程序之间共享的公用子例程。

在运行某个程序时,如果看到如下信息:

“Incompatiblelibraryversion.”则表明需要将该库升级到程序所需要的版本。

库是向下兼容的,也就是说,用老版本库编译的程序可以在新安装的版本库上运行,反之则不行。

Linux库函数的升级是一项重要的工作,往往与其它软件包的升级有一定关联作用,所以操作前一定要备份文件。

下面看一下如何把Glibc2.2.4.13升级至2.3.2版本,其过程如下:

1.下载.gz压缩文件并解压

在GUNC网站下载的四个.gz压缩文件,解压至一临时目录中:

cd/usr/caolinux

tarxzvfglibc-2.3.2.tar.gz

cdglibc-2.3.2

tarxzvf../glibc-linuxthreads-2.3.2.tar.gz

tarxzvf../glibc-crypt-2.3.2.tar.gz

tarxzvf../glibc-localedata-2.3.2.tar.gz

2.建立库函数的安装目录

mkdir/usr/higlibc

cd/usr/higlibc

3.建立编译目录

mkdircao

cdcao

./configure--enable-add-ons=linuxthreads,crypt,localedata-prefix=/usr/higlibc

4.编译与安装

make

makecheck

makeinstall

5.改变数据库的链接

ln-s/usr/higlibc/lib/ld-linux.so.2/lib/ld-linux.so.2

然后,修改/etc/ld.so.conf,加入一行/usr/higlibc/lib,执行下面代码:

ldconfig-v

更新/etc/ld.so.cache的内容,列出每个库的版本号,扫描目录和所要创建及更新的链接。

6.更改GCC设置

cd/usr/lib/gcc-lib

cp-ri386-redhat-linuxhiglibc

7.更新符号链接

cd/usr/higlibc/include

ln-s/usr/src/linux/include/linux

ln-s/usr/src/linux/include/asm

ln-s/usr/X11R6/include/X11

8.测试并完成

五。

高级共享库特性

1.soname

共享库的一个非常重要的,也是非常难的概念是soname——简写共享目标名(shortforsharedobjectname)。

这是一个为共享库(.so)文件而内嵌在控制数据中的名字。

如前面提到的,每一个程序都有一个需要使用的库的清单。

这个清单的内容是一系列库的soname,如同ldd显示的那样,共享库装载器必须找到这个清单。

soname的关键功能是它提供了兼容性的标准。

当要升级系统中的一个库时,并且新库的soname和老的库的soname一样,用旧库连接生成的程序,使用新的库依然能正常运行。

这个特性使得在Linux下,升级使用共享库的程序和定位错误变得十分容易。

在Linux中,应用程序通过使用soname,来指定所希望库的版本。

库作者也可以通过保留或者改变soname来声明,哪些版本是相互兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。

查看/usr/local/lib目录,分析MiniGUI的共享库文件之间的关系

2.共享库装载器

当程序被调用的时候,Linux共享库装载器(也被称为动态连接器)也自动被调用。

它的作用是保证程序所需要的所有适当版本的库都被调入内存。

共享库装载器名字是ld.so或者是ld-linux.so,这取决于Linuxlibc的版本,它必须使用一点外部交互,才能完成自己的工作。

然而它接受在环境变量和配置文件中的配置信息。

文件/etc/ld.so.conf定义了标准系统库的路径。

共享库装载器把它作为搜索路径。

为了改变这个设置,必须以root身份运行ldconfig工具。

这将更新/etc/ls.so.cache文件,这个文件其实是装载器内部使用的文件之一。

3.使用dlopen

另外一个强大的库函数是dlopen()。

该函数将打开一个新库,并把它装入内存。

该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。

比如ApacheWeb服务器利用这个函数在运行过程中加载模块,这为它提供了额外的能力。

一个配置文件控制了加载模块的过程。

这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了。

可以在自己的程序中使用dlopen()。

dlopen()在dlfcn.h中定义,并在dl库中实现。

它需要两个参数:

一个文件名和一个标志。

文件名可以是我们学习过的库中的soname。

标志指明是否立刻计算库的依赖性。

如果设置为RTLD_NOW的话,则立刻计算;如果设置的是RTLD_LAZY,则在需要的时候才计算。

另外,可以指定RTLD_GLOBAL,它使得那些在以后才加载的库可以获得其中的符号。

当库被装入后,可以把dlopen()返回的句柄作为给dlsym()的第一个参数,以获得符号在库中的地址。

使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。

六、LINUX下动态链接库的使用

重要的dlfcn.h头文件

LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。

下面详细说明一下这些函数。

1。

dlerror

原型为:

constchar*dlerror(void);

当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

2。

dlopen

原型为:

void*dlopen(constchar*filename,intflag);

dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

filename:

如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。

(1)用户环境变量中的LD_LIBRARY值;

(2)动态链接缓冲文件/etc/ld.so.cache

(3)目录/lib,/usr/lib

flag表示在什么时候解决未定义的符号(调用)。

取值有两个:

1)RTLD_LAZY:

表明在动态链接库的函数代码执行时解决。

2)RTLD_NOW:

表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。

3。

dlsym:

取函数执行地址

原型为:

void*dlsym(void*handle,char*symbol);

dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。

由此地址,可以带参数执行相应的函数。

如程序代码:

void(*add)(intx,inty);/*说明一下要调用的动态函数add*/

add=dlsym("xxx.so","add");/*打开xxx.so共享库,取add函数地址*/

add(89,369);/*带两个参数89和369调用add函数*/

4。

dlclose:

关闭动态链接库

原型为:

intdlclose(void*handle);

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

 

linux库文件的使用和生成

所以为了使用这些库,通常使用建立符号连接的方式。

ln-slibhello.so.1.0libhello.so.1ln-slibhello.so.1libhello.so使用库当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。

然而,对动态库而言,就不是这样。

动态库会在执行程序内留下一个标记‘指明当程序执行时,首先必须载入这个库。

由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。

现在假设有一个叫hello的程序开发包,它提供一个静态库libhello.a一个动态库libhello.so,一个头文件hello.h,头文件中提供sayhello()这个函数/*hello.h*/voidsayhello();另外还有一些说明文档。

这一个典型的程序开发包结构1.与动态库连接linux默认的就是与动态库连接,下面这段程序testlib.c使用hello库中的sayhello()函数/*testlib.c*/#include#includeintmain(){sayhello();return0;}使用如下命令进行编译$gcc-ctestlib.c-otestlib.o用如下命令连接:

$gcctestlib.o-lhello-otestlib在连接时要注意,假设libhello.o和libhello.a都在缺省的库搜索路径下/usr/lib下,如果在其它位置要加上-L参数与与静态库连接麻烦一些,主要是参数问题。

还是上面的例子:

$gcctestlib.o-otestlib-WI,-Bstatic-lhello注:

这个特别的"-WI,-Bstatic"参数,实际上是传给了连接器ld.指示它与静态库连接,如果系统中只有静态库当然就不需要这个参数了。

如果要和多个库相连接,而每个库的连接方式不一样,比如上面的程序既要和libhello进行静态连接,又要和libbye进行动态连接,其命令应为:

$gcctestlib.o-otestlib-WI,-Bstatic-lhello-WI,-Bdynamic-lbye3.动态库的路径问题为了让执行程序顺利找到动态库,有三种方法:

(1)把库拷贝到/usr/lib和/lib目录下。

(2)在LD_LIBRARY_PATH环境变量中加上库所在路径。

例如动态库libhello.so在/home/ting/lib目录下,以bash为例,使用命令:

$exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:

/home/ting/lib(3)修改/etc/ld.so.conf文件,把库所在的路径加到文件末尾,并执行ldconfig刷新。

这样,加入的目录下的所有库文件都可见、4.查看库中的符号有时候可能需要查看一个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。

库既可以是静态的也可以是动态的。

nm列出的符号有很多,常见的有三种,一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;一种是库中定义的函数,用T表示,这是最常见的;另外一种是所谓的“弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。

例如,假设开发者希望知道上央提到的hello库中是否定义了printf():

$nmlibhello.so|grepprintfUprintfU表示符号printf被引用,但是并没有在函数内定义,由此可以推断,要正常使用hello库,必须有其它库支持,再使用ldd命令查看hello依赖于哪些库:

$lddhellolibc.so.6=>/lib/libc.so.6(0x400la000)/lib/ld-linux.so.2=>/lib/ld-linux.so.2(0x40000000)从上面的结果可以继续查看printf最终在哪里被定义,有兴趣可以goon生成库第一步要把源代码编绎成目标代码。

以下面的代码为例,生成上面用到的hello库:

/*hello.c*/#includevoidsayhello(){printf("hello,world");}用gcc编绎该文件,在编绎时可以使用任何全法的编绎参数,例如-g加入调试代码等:

gcc-chello.c-ohello.o1.连接成静态库连接成静态库使用ar命令,其实ar是archive的意思$arcqslibhello.ahello.o2.连接成动态库生成动态库用gcc来完成,由于可能存在多个版本,因此通常指定版本号:

$gcc-shared-Wl,-soname,libhello.so.1-olibhello.so.1.0hello.o另外再建立两个符号连接:

$ln-slibhello.so.1.0libhello.so.1$ln-slibhello.so.1libhello.so这样一个libhello的动态连接库就生成了。

最重要的是传gcc-shared参数使其生成是动态库而不是普通执行程序。

-Wl表示后面的参数也就是-soname,libhello.so.1直接传给连接器ld进行处理。

实际上,每一个库都有一个soname,当连接器发现它正在查找的程序库中有这样一个名称,连接器便会将soname嵌入连结中的二进制文件内,而不是它正在运行的实际文件名,在程序执行期间,程序会查找拥有soname名字的文件,而不是库的文件名,换句话说,soname是库的区分标志。

这样做的目的主要是允许系统中多个版本的库文件共存,习惯上在命名库文件的时候通常与soname相同libxxxx.so.major.minor其中,xxxx是库的名字,major是主版本号,minor是次版本号

 

库的定义和种类

所谓编程库就是指始终可以被多个Linux软件项目重复使用的代码集。

库是Linux软件开发所追求的目标,C语言就是一个例子,它包含了几百个可以重复使用的例程和调试程序的工具代码,其中包括函数。

如果每次编写新程序都要重新写这些函数会感到非常麻烦。

使用编程库有两个主要优点,一是可以简化编程,实现代码重复使用;二是可以直接使用许多经过调试的测试和调试工具。

Linux下的库文件分为共享库和静态库两大类,它们两者的差别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。

Linux的库一般在/lib或/usr/lib目录下。

lib是库(Library)的英文缩写,它主要存放系统的链接库文件,没有该目录则系统就无法正常运行。

/lib目录中存储着程序运行时使用的共享库。

通过共享库,许多程序可以重复使用相同的代码,并且这些库可以存储在一个公共的位置上,因此能减小运行程序的大小。

这个目录包含程序在链接时使用的各种库。

图1是笔者/usr/lib(RedHatLinux9.0)目录快照。

 

图1/usr/lib目录快照

 

区分库类型最好的方法是看它们的文件后缀,通常共享库以.so(SharedObject的缩写)结尾,静态链接库通常以.a结尾(Archive的缩写)。

在终端缺省情况下,共享库通常为绿色,而静态库为黑色。

库的命名和编号

在Linux下开发应用程序时,绝大多数情况使用的都是C语言,目前Linux下最常用的C语言编译器是GCC,它的全称是GNUCompilerCollection,下文中的库介绍都以它为例。

GCC是直接建立在内核基础上的,是Linux操作系统外层的图形界面开发工具(Qt、GTK+)和网络应用开发工具(PHP、Prel、Python)的基础和过渡。

掌握了底层开发工具,可以加快和优化外层应用开发,从而达到开发速度和开发质量的和谐统一。

Glibc2.3.2是最新版的GNUC库。

它目前不需要修改就可以在GNUHurd、Linuxi386、m68k,以及Alpha系统上执行,并且从2.1版开始加入了对LinuxPowerPC、MIPS、Sparc、Sparc64等系统的支持。

如果想查看自己Linux计算机的Glibc版本可以使用下面命令:

 

rpm-qa|grepglibc

glibc-common-2.3.2-11.9

glibc-2.3.2-11.9

glibc-devel-2.3.2-11.9

 

由上可见,RedHatLinux9.0使用的Glibc版本是2.3.2。

1.库的命名

库的命名比较简单,第一个特点是所有的库以lib开头,GCC命令在在-l选项所指定的文件名前会自动加入lib。

第二个特点文件名以.a结尾的库是静态库。

第三个特点文件名是.so的库为共享库。

默认情况下,GCC在链接时优先使用共享库,只有当共享库不存在时才考虑使用静态库。

2.库的编号

库的编号格式如下:

 

library_name.major.num.minor_.min.pathch_num

 

例如,笔者RedHatLinux9.0的GUN数据库是libgdbm.so.0.0.2,详细表述如下:

◆library_name是libc.so(标准C库);

◆major_num是2(主版本号);

◆minor_.min是0(次版本号);

◆pathch_num是0(补丁级别号又称发行号)。

libgdbm.so.0.0.2所在目录是/usr/lib,其大小是24576字节,这是一个ELF(ExecutableandLinkingFo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 动物植物

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1