Hi,欢迎来到嵌入式培训高端品牌 - 华清远见教育科技集团<北京总部官网>,专注嵌入式工程师培养15年!
当前位置: > 华清远见教育科技集团 > 嵌入式学习 > 讲师博文 > C语言共享库的制作
C语言共享库的制作
时间:2017-01-04作者:华清远见

1)基本概念

共享库也是.o文件的集合,但是这些文件由编译器按照一种特殊的方式生成(Linux中,共享库文件为"ELF"格式,共享库已经具备了可执行条件)。

共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

模块中各个成员的地址(变量引用和函数)都是相对地址。使用此共享库的程序在运行时,共享库被动态加载到内存中并和主程序在内存中进行链接。多个可执行程序可以共享库文件的代码段(不共享数据段)。

共享库的成员对象可以被执行(由libdl.so提供支持)。

2)如何建立和使用共享库

1、编写源文件:

源码一:my_strcpy.c:(实现一个strcpy的功能)

#include <stdio.h>
        #include <string.h>
        #include <stdlib.h>

void my_strcpy(char *des, const char *src)
        {
                while (*des++ = *src++);
        }

源码二:my_strcmp.c(实现一个strcmp的功能)

#include <stdio.h>
        #include <string.h>
        #include <stdlib.h>

int my_strcmp(const char *obj1, const char *obj2)
        {
                while (*obj1 && *obj2)
                {
                        if (*obj1 - *obj2)
                        {
                                return (*obj1 - *obj2);
                        }
                        else
                        {
                                obj1++;
                                obj2++;
                        }
                }
                return 0;
        }

2、生成.o文件

gcc -fPIC -c my_strcpy.c my_strcmp.c

注意:这里与建立静态库有所不同的是要加上参数-fPIC,意思是生成与位置无关的代码,因为共享库链接的时候使用的都是相对地址(偏移量),所以必须指定这项参数。

3、建立共享库

gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1 *.o

-shared代表要建立共享库,-Wl, option代表把选项option传给链接器,这里就是把soname传给链接器,用于指定共享库的版本编号,-o后面是实际的共享库名称。注意,这里共享库的版本号和它的实际名称一样,这样我们就不必再建立符号链接指向实际的名称,可以省去一个符号链接。共享库的版本号是保存在实际的库里的,我们可以执行这个命令:readelf –a libmylib.so.1 | grep libmylib.so.1,就可以看到:

0x0000000e (SONAME)                Library soname: [libmylib.so.1]

共享库里的这个版本编号是留给动态加载器(dl)用的,dl会到库里去找这个版本号,完成动态加载的功能。

现在动态加载器可以找到我们创建的共享库了,不过编译器暂时还找不到这个库,我们必须建立一个软链接到实际的库文件,而且这个软链接的文件名必须是以lib开头,以.so结尾的,这是编译器要求的格式。所以我们只需要执行:ln –s libmylib.so.1 libmylib.so就可以了。

也就是说,共享库和静态库不同,静态库只是在编译的时候需要,而共享库在编译和加载的时候都需要,因为它并没有被真正编译进可执行程序,程序里面只是保存了对库函数的符号引用。

4、测试共享库

测试代码main.c和静态库的相同

编译:gcc –o main main.c –L. –lmylib

我们会发现:编译可以通过,但是执行./main终端会打印出:

./main: error while loading shared libraries: libmylib.so.1: cannot open shared object file: No such file or directory

这条信息说明加载共享库的时候出错,加载器找不到libmylib.so.1这个共享库,为什么?这是因为加载器默认的情况下只会到系统指定的路径下去加载共享库,指定路径包括:/usr/lib/和/lib/。要解决这个问题可以有两个办法,一是执行:export LD_LIBRARY_PATH=./把当前路径添加到加载器加载路径的环境变量里面去,当然这样做的话每打开一次终端都要重新执行一遍这个命令;第二种方法是可以在/usr/lib/下或者/lib/下建立一个软链接libmylib.so.1指向真正的库文件libmylib.so.1,这样加载每次都可以找到我们的库文件了,不过我们不推荐这种做法,除非我们制作的共享库很成熟而且经常被用到。

这次再执行./main就可以看到结果:

hello linux.
        hello world.
        s1 < s2

3)小结

共享库也是.o文件的集合,但它是ELF格式的。

共享库只是在程序开始运行时载入,在编译时,只要简单地指定需要使用的库函数。

动态库是共享库的另一种变化形式。动态库也是在程序运行时载入,但与共享库不同的是,使用的库函数不实在程序运行开始,而是在程序中的语句需要使用该函数时才载入。动态库可以在程序运行期间释放动态库所占用的内存。共享库和动态库并没有在程序中包含库函数的内容,只是包含了对其的引用,因此代码的规模较小。

发表评论
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)