函数库:静态库和动态库


1、函数库

    函数库其实就是一些写好的函数集合,方便别人的复用。实现的封装之后,最终的目的都是给别人调用。

2、库的形式

   库的形式分:动态链接库和静态链接库。

优点:

    (1)库文件都是被编译好的二进制文件,别人看不到源代码,可以保持保密;(2)同时不会因为不小心被修改出现问题,便于维护。

LINUX 下的库学习:

静态链接库:.a 文件

    其实就是将多函数,做编译但是不链接生成的 .o 文件,使用 ar 工具打包为 .a 的文件。编译的阶段,当调用这些库的时候,链接器就会去 .a 的库文件中拿出被调用的那个函数的 .o 文件进行链接到而执行的程序。这个过程是将库函数的 .o 的文件与主函数的文件一起打包成为一个可执行的文件,所以这个可执行的文件就会很大。加载到内存的时候,也是会占据很大的空间,生命周期是整个程序的生命周期。

    缺点: 当多个可执行的文件包含了相同的库文件的时候,比如 a,b 都包含了 printf 这个库,那么内存就被会同时存在两个相同的库,多么的浪费内存啊。

动态链接库:.so 文件

    动态链接库的链接方式是,在编译的阶段是不会将涉及到的库文件链接到代码中的,而是制作了一个标记;当程序运行的时候需要相应的库文件的时候,就将相应的库文件加载到内存进行使用,不用的时候就进行释放。所以使用动态链接库的时候,而到的可执行的文件会比较的小,避免了空间的浪费。

   优点:动态库是在需要的时候才被进行才入到内存,所以解决了动态库的更新、部署、发布代码上面的麻烦,用户只需要加载新的动态库,做增量更新就可以了。

gcc 中编译链接默认使用的是动态链接的方式的,所以当要使用静态链接的方式的时候,就需要添加: -static

gcc a.c -o a. -static

windows:

    静态库 : .lib 文件

    动态库 : .dll 文件

3、制作自己的静态链接库

    自己制作静态库,最主要的是生成自己的 .a 文件和 .h 文件。

(1)制作自己库函数原材料

test.c 就是我们制作库函数材料:

#include<stdio.h>
int fun1(int a,int b)
{
    return a + b;
}
int fun2(int a, int b)
{
    return a * b;
}

    定义了两个函数的实现方式。

(2)生成头文件

    上一步实现了 test.c 的实现的方式,所以我们必须有与库材料同名的头文件。

test.h

int fun1(int a,int b);
int fun2(int a,int b);

    头文件其实就是将实现的材料的函数原型进行声明。记得是原型。

(3)生成库文件

    Makefile:

all:
    gcc test.c -o test.o -c
    ar -rc libtest.a test.o

    将 test.c 生成为 .o 的文件,这里使用了: -c 进行了指定为只是进行编译,但是没有进行链接。记住 c 是小写的哦。

    使用 ar 打包工具生成 libtest.a。这里的库的名字不能是随意进行取名的,因为文件是 test.o 的文件,所以库的名字只能是 libtest.a,也就是lib + 文件的名字。


(4)使用自己的静态链接库

    上面的步骤已经得到了我们需要的 .h 和 .a 的文件。

自己的代码:

#include<stdio.h>
#include"test.h"
int main(int argc, char *argv[])
{
    int i;
    i = fun1(1, 2);
    printf("i = %d\n", i);
    i = fun2(3, 4);
    printf("i = %d\n", i);
}

编译的方式:

gcc testlib.c -o testlib -L /home/qxj511/python -ltest

    -L : 指定库文件的路径,这里指定的是绝对的路径,当前路径的话,可以用电进行表示。

    -ltest : 执行库的名字。上面我们生成的库的名字是 libtest.a,而我们这里是使用了小写的 l 代表了 lib,所以就可以使用 libtest 去代替。

(5)nm 命令

    nm 命令是可以查看一个动态库和静态库里面的符号信息。、

nm libtest.a 
输出的信息:
test.o:
00000000 T fun1
0000000d T fun2

    可见库里面只是包含了 一个 test.o(一般的库文件都是包含大量的 .o 的文件),而 test.o 里面只是包含了两个 函数。

4、制作自己的动态链接库

    制作的材料使用上面的 test.c,头文件的话也是 test.h,这里都不做修改。

(3)生成动态链接库

Makefile:

gcc test.c -o test.o -c -fPIC
gcc -o libtest.so test.o -shared

-fPIC :执行生成的 .o 的文件是位置无关码的。

-share : 以生成动态链接库

    这样就得到了 .h 和 .so库文件了。

(4)使用自己的动态链接库

gcc testlib.c -o testlib -L /home/qxj511/python -ltest

    编译一次性成功,但是运行的时候确实报错了。原因是:动态链接库是实现动态加载的,当需要调用相关库的时候,去加载相应的库,而默认加载动态库的路径是系统的固定路径,所以解决的办法:

方法一:将自己的动态库放到系统的目录: /usr/lib/ 目录里面。

方法二:添加 LD_LIBRARY_PATH。 LD_LIBRARY_PATH 是系统加载路的路径,操作系统加载固定目录的时候,先回去 LD_LIBRARY_PATH 去寻找相应的库文件,当没有找到的时候采取固定的目录: /usr/lib/ 下寻找。、

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/qxj511/python

    通过 export 命令添加了库寻找的路径。

(5)ldd 命令

    ldd 命令的作用是查看文件依赖哪些的共享库,并且查看这些库是否可以被找到,能被解析。

root@qxj511:~/python# ldd testlib
    linux-gate.so.1 =>  (0xb76fe000)
    libtest.so (0xb76f9000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb753c000)
    /lib/ld-linux.so.2 (0xb76ff000)

    可见,我们的可执行的文件是依赖于四个库。上面的意思是这四个库都可以被找到,都是指向于数字地址,。当没有找到这些库的时候,就会出现: n、

not found。

posted @ 2015-11-06 19:56  qxj511  阅读(1318)  评论(2编辑  收藏  举报