Chinaunix首页 | 论坛 | 博客
  • 博客访问: 851006
  • 博文数量: 190
  • 博客积分: 7021
  • 博客等级: 少将
  • 技术积分: 1752
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-17 19:26
文章分类

全部博文(190)

文章存档

2014年(9)

2011年(32)

2010年(149)

我的朋友

分类: LINUX

2010-10-13 09:50:59

    总体概述,C语言的函数库可以有三种使用的形式:静态、共享和动态。
    其中静态库的代码在编译时就已连接到开发人员开发的应用程序中。
    而共享库只是在程序开始运行时才载入,在编译时, 只是简单地指定需要使用的库函数就可以了。
    动态库则是共享库的另一种变化形式,它也是在程序运行时载入,但与共享库不同的是, 使用的库函数不是在程序运行开始,而是在程序中的语句需要使用该函数时才载入,动态库可以在程序运行期间释放动态库所占用的内存,腾出空间供其它程序使用。
    由于共享库和动态库并没有在程序中包括库函数的内容,只是包含了对库函数的引用,因此代码的规模比较小。

 

    Linux下的库文件分为共享库和静态库两大类,它们两者的差别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。
    静态函数库:每次当应用程序和静态连接的函数库一起编译时,任何引用的库函数中的代码都会被直接包含进最终的二进制程序。
    共享函数库:包含每个库函数的单一全局版本,它在所有应用程序之间共享。这一过程背后所涉及的机制相当复杂,但主要依靠的是现代计算机的虚拟内存能力,它允许包含库函数的物理内存安全地在多个独立用户程序之间共享。
    区分库类型最好的方法是看它们的文件后缀,通常共享库以.so(Shared Object的缩写)结尾,静态链接库通常以.a结尾(Archive的缩写)。在终端缺省情况下,共享库通常为绿色,而静态库为黑色。
    已经开发的大多数库都采取共享库的方式,Linux系统中目前可执行文件的标准格式为ELF(Executable and Linkable Format)格式。ELF格式的可执行文件使得共享库能够比较容易地实现:
.a的是为了支持较老的a.out格式的可执行文件,静态库文件, 可以用ar 命令生成。
.so的是支持elf格式的可执行文件的库,动态库文件,编译时加上指定的选项即可生成。

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

 

    命名规则
    GNU库的使用必须遵守Library GNU Public License(LGPL许可协议)。该协议与GNU许可协议略有不同, 开发人员可以免费使用GNU库进行软件开发, 但必须保证向用户提供所用的库函数的源代码。
    库文件名由前缀lib和库名以及后缀组成,根据库的类型不同,后缀名也不一样。共享库的后缀名由.so和版本号组成, 静态库的后缀名为.a。
静态库:libname.a
共享库:libname.so.major.minor.patchlevel

name : 可以是任何字符串, 用来唯一标识某个库,可以是一个或几个字符、甚至一个字母。
major : 主版本号
minor : 次版本号
patchlevel : 补丁版本

 

    在linux中显示一个executable program对库的依赖引用关系的命令是ldd(Library Dependency Display)。Eg:
[mysql@my101 ~]$ ldd /u01/mysql/bin/mysql
        libncursesw.so.5 => /usr/lib/libncursesw.so.5 (0x00845000)
        libpthread.so.0 => /lib/tls/libpthread.so.0 (0x00938000)
        libmysqlclient.so.16 => /u01/mysql/lib/mysql/libmysqlclient.so.16 (0x00c8d000)
        libcrypt.so.1 => /lib/libcrypt.so.1 (0x0066b000)
        libnsl.so.1 => /lib/libnsl.so.1 (0x00583000)
        libz.so.1 => /usr/lib/libz.so.1 (0x00926000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x009a2000)
        libm.so.6 => /lib/tls/libm.so.6 (0x00820000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00996000)
        libc.so.6 => /lib/tls/libc.so.6 (0x006ec000)
        /lib/ld-linux.so.2 (0x006cd000)
这里我们特别额外说明下最后一行ld-linux.so库。当程序被调用的时候, Linux 共享库装载器(动态连接器)也自动被调用,它的作用是保证程序所需要的所有适当版本的库都被调入内存。而可能的共享库装载器的名字就是 ld.so 或者是 ld-linux.so (取决于 Linux libc 的版本)。

 

    接下来我们以例子的形式来讲解如何用gcc创建静态库和动态共享库。

    创建静态库
$ cat base.c
void prt(){
        printf("this is the base test\n");
}

$ cat st.c
#include
int main(){
        prt();
        return 0;
}

 

$ gcc -c base.c -o base.o
$ ar cqs libbase.a base.o   -- 
使用ar命令来生成静态库文件。

    Gcc使用 -static 选项来生成静态执行执行文件,也就是使用该选项,它会把静态库文件(如果c程序中有引用的话)的内容复制到相应的c文件中,一起编译生产可执行文件。

$ gcc st.c -static base.o -o st2 -- 直接使用base.o生产静态执行文件

$ gcc st.c -static -L. -lbase -o st3  -- 通过L指定目录,-l指定静态库文件名称(libbase.a)来生成静态执行文件

$ gcc st.c -static libbase.a -o st4 -- 直接通过指定静态库文件详细名来生成静态执行文件

$ gcc st.c libbase.a -o st1  -- 这种情况其实生成的还是动态执行文件,但是却使用了静态库libbase.a内容,这和前面的方法有什么区别呢,下面再议。

    我们下面来看下上面几种文件的区别,先看大小

$ls -lthc

total 2.1M

-rwxr-xr-x  1 mysql dba 504K Aug 31 17:41 st2

-rwxr-xr-x  1 mysql dba 504K Aug 31 17:36 st4

-rwxr-xr-x  1 mysql dba 504K Aug 31 17:36 st3

-rwxr-xr-x  1 mysql dba 6.8K Aug 31 17:34 st1

-rw-r--r--  1 mysql dba 1.7K Aug 31 17:34 libbase.a

-rw-r--r--  1 mysql dba 1.5K Aug 31 17:32 base.o

-rw-r--r--  1 mysql dba   70 Aug 31 17:25 st.c

-rw-r--r--  1 mysql dba   58 Aug 31 17:25 base.c

-rw-r--r--  1 mysql dba 9.5K Aug 31 13:33 a.sql

-rw-r--r--  1 mysql dba  922 Aug 30 22:24 a.c

    可以使用ldd命令,查看执行文件的库函数引用情况

$ldd st1

        libc.so.6 => /lib64/tls/libc.so.6 (0x0000003848b00000)

        /lib64/ld-linux-x86-64.so.2 (0x0000003848700000)

$ldd st2

        not a dynamic executable

$ldd st3

        not a dynamic executable

$ldd st4

        not a dynamic executable

    使用 -static 选项,它的作用是禁止使用动态库,因此它编译出来的东西一般都比较大,无需任何动态链接库都可以运行。如果不使用这个选项,如我们上面的最后一种情况,它其实生成的是动态执行文件,只是其中一起编译的动态库文件libbase.a在编译的时候被静态到要编译的文件st.c中去了,而其他部分(如printf函数)还是使用动态库文件的。

 

    创建共享库
$ cat sh.c
#include
int main()
{
        prt();
        return 0;
}

$ gcc -fPIC -c base.c -o base.o
    -fPIC参数标记告诉gcc产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样,编译输出的文件base.o可以被用于建立共享函数库,下面只需使用gcc的“-shared”参数来申明编译为共享库即可:
$ gcc -shared base.o -o libbase.so
    然后编译sh.c的时候,我们需要更多的参数让gcc知道如何寻找共享库:
$ gcc -L. -lbase sh.c -o sh
    -L参数指定到哪个附加路径下面去寻找共享库,现在我们指定在当前目录下面寻找
    -l参数指定链接到哪个共享库上面,我们传的参数base,那么gcc就会自动链接到libbase.so这个共享库上面
    下面开始运行连接后的可执行文件:
$ ./sh
./sh: error while loading shared libraries: libbase.so: cannot open shared object file: No such file or directory
    发现出错,这是因为上面在做连接编译的时候,虽然通过-L和-l指定了连接共享库路径,从而sh.c文件能编译成功为可执行文件sh。但是当你执行sh时,由于没有指定该文件所引用的共享库地址,那么ld.so就找不到相应的共享库libbase.so,于是也就无法运行成功了。

阅读(2178) | 评论(1) | 转发(0) |
0

上一篇:typedef

下一篇:C语言中的基本画图函数

给主人留下些什么吧!~~

chinaunix网友2010-10-13 20:12:52

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com