函数库简介
函数库是由若干目标文件按某种格式构成的集合,而目标文件是由源文件经过编译生成的中间代码。软件开发的过程中往往会积累许多可复用代码,这些代码经过严格的测试和反复的使用,证明是可靠的。为了提高软件的开发效率,可将这些代码编译,并分类打包成函数库,供其他项目使用。
函数库可分为两种类型,静态库和共享库,它们在与应用程序的链接方式上具有不同的特点:
- 应用程序在链接静态库时,将使用的静态库对象嵌入至可执行文件中;
- 应用程序在链接共享库时,仅在可执行文件中保留加载目标对象所需的信息,在调用时才真正将目标对象加载至内存。
静态库
静态库简介
静态库由ar工具创建。经编译的应用程序和静态库链接时,链接器将静态库中被调用的对象嵌入至可执行文件中,这样在没有静态库的环境下,应用程序也能独立运行。
静态库文件的命名规则是libxxx.a,以lib作为固定前缀,以.a作为后缀。
静态库特征
由于在生成的可执行文件中包含了所有需要的目标对象,因此静态库具有以下特点:
- 运行时无需外部库的支持
可执行文件中由于嵌入了所需的静态库目标对象,因此可以脱离静态库独立运行。 - 较高的运行速度
由于可执行文件中包含了所有需要的静态库目标对象,在运行时不需加载其他目标对象,因此应用程序具有较高的运行速度。 - 可执行文件具有较大的体积
由于可执行文件中嵌入了所需的静态库目标对象,因此增加了可执行文件的体积。 - 不易维护
由于库中的目标文件被链接进最终的可执行文件,因此当程序功能被修改后,必须重新进行链接。
静态库创建
假设有两个c源文件a.c和b.c,a.c中使用原型为int add(int x, int y)的函数实现了两个整数相加的功能,b.c中使用原型为int multi(int x, int y)的函数实现了两个整数相乘的功能,则创建静态库的步骤如下:
-
编译两个c源文件
使用如下指令生成两个目标文件a.o和b.o$ gcc -c -Wall a.c $ gcc -c -Wall b.c
-
创建静态库
使用ar工具,利用所生成的两个目标文件生成静态库libdemo.a$ ar -cru libdemo.a a.o b.o
其中,选项-c告诉ar创建一个新的静态库,除非该静态库已存在;选项-r告诉ar替换已存在的目标文件;选项-u告诉ar被替换的目标文件必须是最新的。
-
定义静态库应用接口
为了使用libdemo.a静态库,需要定义静态库的应用接口,如下所示#ifndef _DEMOLIB_API_H_ #define _DEMOLIB_API_H_ extern int add(int x, int y); extern int multi(int x, int y); #endif
静态库使用
假设在c源文件demo.c中调用了静态库libdemo.a中的两个库函数add()和multi(),则应使用如下指令编译生成可执行文件demo:
$ gcc demo.c -L. -ldemo -o demo
其中,-L.表示静态库位于当前目录,-ldemo表示链接libdemo.a库。
当库与c源文件不处于同一目录下时,需要使用如下的指令生成可执行文件demo:
$ gcc demo.c -L <directory> -ldemo -o demo
其中directory为静态库libdemo.a所在的文件夹路径。假设libdemo.a位于../lib目录下,则上面的指令就相应地为
$ gcc demo.c -L ../lib -ldemo -o demo
共享库
共享库简介
共享库也称为动态加载库。经编译后的应用程序在和共享库链接时,链接器在库中检查所需的符号信息,例如函数和变量,只在生成的可执行文件中记录这些信息的来源。因此与静态库不同的是,链接器没有将共享库中的目标对象嵌入到可执行文件中,所以离开了共享库的支持,应用程序就无法运行。
共享库文件的命名规则是libxxx.so,以lib作为固定前缀,以.so作为后缀。
共享库特征
与静态库相比,共享库具有以下特点:
- 可执行文件体积小
由于没有将共享库中的目标对象嵌入至应用程序,因此可执行文件具有较小的体积。 - 容易维护
共享库中的目标对象发生改变时,应用程序不需要重新编译。 - 不能离开动态库独立运行
由于可执行文件未包含共享库中调用的目标对象,因此不能离开共享库独立运行。 - 运行速度较慢
由于应用程序在启动时需要加载共享库,因此运行速度会受到一定影响。
共享库创建
仍假设有两个c源文件a.c和b.c,a.c中使用原型为int add(int x, int y)的函数实现了两个整数相加的功能,b.c中使用原型为int multi(int x, int y)的函数实现了两个整数相乘的功能,则创建共享库的步骤如下:
-
编译两个c源文件
使用如下指令生成两个目标文件a.o和b.o$ gcc -c -fPIC a.c $ gcc -c -fPIC b.c
其中,选项-fPIC告诉gcc创建地址独立的目标文件。
-
创建共享库
使用gcc,利用所生成的两个目标文件生成共享库libdemo.so$ gcc -shared a.o b.o -o libdemo.so
其中,选项-shared告诉gcc创建一个共享库。
共享库使用
假设在c源文件demo.c中调用了共享库libdemo.so中的两个库函数add()和multi(),则应使用如下指令编译生成可执行文件demo:
$ gcc demo.c -L. -ldemo -o demo
其中,-L.表示静态库位于当前目录,-ldemo表示链接libdemo.so库。
如果目录下同时存在libdemo.a和libdemo.so,则默认情况下将优先使用共享库,也可加上选项-static指定链接静态库。
当库与c源文件不处于同一目录下时,需要使用如下的指令生成可执行文件demo:
$ gcc demo.c -L <directory> -ldemo -o demo
其中directory为共享库libdemo.so所在的文件夹路径。假设libdemo.so位于../lib目录下,则上面的指令就相应地为
$ gcc demo.c -L ../lib -ldemo -o demo
注:执行这条指令时可能会报找不到库的错误,这是由于没有将共享库所在的路径添加到系统加载共享库时所查找的默认路径中,解决方法如下。
-
临时修改
在命令行中直接输入以下指令:$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<directory>
其中directory为共享库所在的文件路径。执行后,关闭当前终端并重新打开一个新终端,使以上配置生效。
-
用户级修改
使用如下指令打开~/.bashrc文件$ vim ~/.bashrc
敲i键进入编辑模式,在文件的最后添加如下指令后,按Esc键退出编辑模式,并输入:wq保存并退出。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<directory>
directory同样为共享库所在的文件路径。
执行刚修改的初始化文件,使之立即生效:$ source ~/.bashrc
系统级修改
未尝试该方法,可参见链接:CSDN。