创建和使用静态库
1. 创建目录
mkdir –p test/sub
2. 在子目录sub/下编写hello.c和hello.h
/*****hello.c*****/
#include <stdio.h>
#include “hello.h”
void hello()
{
printf(“Hello!/n”);
}
/*****hello.h*****/
#include <stdio.h>
void hello();
3. 编译链接/打包
gcc –c hello.c –o hello.o
ar cqs libhello.a hello.o
4. 在主目录test/下编写main.c
#include <stdio.h>
#include “sub/hello.h”
int main()
{
hello();
retrun 0;
}
5. 编译链接
gcc –c main.c –o main.o
gcc main.o –o main.exe –L “sub/” –lhello #dynamically linked (uses shared libs)
或gcc main.o –o main.exe –static –L “sub/” –lhello # statically linked
--------------------------------------------------------------------------------------------------
.a(archive) 静态库
.so(shared object) 共享库
静态库只在程序链接时起作用,最终的执行程序脱离静态库运行。
共享库在程序运行时起作用。
--------------------------------------------------------------------------------------------------
共享库的编号约定
格式library_name.major_num.minor_num.patch_num
例如libminigui.so.2.0.0
major_num:当库的变化达到了和以前的版本不能兼容的成都时就要增加主版本号
minor_num:当库有了新变化又能和以前的版本保持兼容时就只改变次版本号
patch_num:为修正库中的错误而进行的改动则会改变补丁级别号,它又叫做发行号(release number)。
以_g和_p结尾的库:
例如libminigui_g.a和libminigui_p.a
它们是基本库的特殊版本,基本库为libminigui.a。以_g结尾的库是调试库,编入了特殊的符号和功能,增加了对采用了这个库的应用程序的调试功能。以_p结尾的库是代码剖析库(profiling),它们包含的代码和符号能进行复杂的代码剖析和性能分析。你如果使用了这两类库,一旦完成了调试和剖析工作,需要使用正常库重新编译你的程序。
--------------------------------------------------------------------------------------------------
库操作的相关命令
nm
功能
列出编入目标文件或二进制文件的所有符号。用途一:查看程序调用什么函数;用途二:查看一个给定的库或目标文件是否提供了所需的函数。
语法
nm [options] file
常用选项
-C 将符号名转换为用户级的名字。在让C++函数名可读方面特别有用。
-s 当用于.a文件时,输出把符号名映射到定义该符号的模块或成员名的索引。
-u 只显示未定义的符号,即在被检查的文件外部定义的文件。
-l 使用调试信息输出定义每个符号的行号,或未定义符号的重要位项。
ar
功能
将多个.o文件组合到一起成为.a文件。
语法
ar [options] lib*.a *.o
常用选项
-c 如果存档文件不存在,则创建,并不显示ar发出的警告。
-q 把*.o添加到存档文件末尾而不检查是否进行替换。
-r 向存档文件中插入.o文件,替换已有的任何同名文件,新成员添加到文档末尾。
-s 创建或升级从符号到.a文件之间的交叉索引映射表,并加入到.a文件中。
等价与ranlib [*.a]。执行该命令后,可用nm –s来查看生成的索引。
ldd
功能
显示可执行程序运行所需的共享库。
语法
ldd [options] file
常用选项
-d 执行重定位并报告所有丢失的函数。
-r 执行对函数和数据对象的重定位并报告丢失的任何函数或数据对象。
ldconfig
功能
在默认搜寻目录(/lib和/usr/lib)及动态库配置文件/etc/ld.so.conf中所列的目录下,搜索出可共享的动态链接库(lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件。缓存文件默认为 /etc/ld.so.cache,此文件保存了已排好序的动态链接库名字列表。
该在系统启动时会运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令。
语法
ldconfig [options] path
例如:ldconfig /root/lib 让系统共享/root/lib目录下的动态链接库,即在/etc/ld.so.cache中添加指定目录下的共享库。[注意]若该目录不在/lib,/usr/lib,/etc/ld.soconf所列的目录列表里,则再次运行ldconf时,此目录下的动态链接库就不被系统共享了。
常用选项
-v 更新/etc/ld.so.cache的内容,列处每个库的版本号,扫描的目录和所有创建和更新的链接。
-p 仅显示/etc/ld.so.cache的内容,即ld.so所知道的共享库的当前列表。
-n ldconf仅扫描-n命令所指定的目录
-f CONF 指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf。
-c CACHE 指定生成的缓存文件为CACHE,系统默认为/etc/ld.so.cache。
当ldconf不带选项时,仅更新高速缓冲文件。
环境变量
$LD_PRELOAD 由空格分隔的共享库列表,在其它库之前加载,使它们有机会覆盖或
重新定义标准库。
$LD_LIBRARY_PATH 由冒号分隔的目录清单,都是共享库搜索时会访问的目录。
--------------------------------------------------------------------------------------------------
创建和使用动态库
创建动态库
1. gcc –fPIC –c hello.c –o hello.o
2. gcc –shared –Wl,-soname,libhello.so –o libhello.1.0.0 hello.o –lc
参数说明
-fPIC 产生与位置无关的代码,并能加载到任何位置。-fpic与之相似,会生成更小更快的
代码,但会有平台的限制。
-shared 告诉编译器生成共享库代码。
-Wl 告诉编译器将后面的参数传给链接器ld。
-soname 指定了共享库的简写共享名(short for shared object name)。
-l 指定链接的库文件名。
-L 向gcc的库文件搜索路径中添加新的目录
使用动态库
方法一
1) 将生成的.so文件复制到系统默认的存放库文件的文件夹,如/usr/lib。如果你复制
libhello.so.1.0.0到/usr/lib,会自动生成一个它的符号链接libhello.so。
2) 以root身份运行ldconfig,更新高速缓冲区/etc/ld.so.cache。
3) gcc –c main.c –o main –lhello
方法二
1) 改变环境变量$LD_LIBRARY_PATH=”your dir”
2) gcc –c main.c –o main –L “sub” –lhello
方法三
1) 在/etc/ld.so.conf中添加你的共享库所在的路径
2) 以root用户身份运行ldconfig
3) gcc –c main.c –o main –L “sub” -lhello
--------------------------------------------------------------------------------------------------
使用动态加载的共享对象
只需在源码中包含<dlfcn.h>,然后在编译命令或makefile中使用-ldl命令与libdl库链接即可。
[注意]不必链接你要使用的库。即使使用一个标准的共享库,也不必按常规方法使用,链接器不会知道共享对象。在编译链接应用程序时,这些模块甚至可以不存在。
dlopen
加载共享对象。如果找到了filename就返回句柄,否则返回NULL。
void *dlopen (const char *filename, int flag);
dlsym
使用共享对象。dlsym在加载对象(由handle指向的共享对象)中搜索在symbol中命名的符号或函数。参数handle须是dlopen返回的句柄;参数symbol是一个标准的C字符串。dlsym
返回指向符号的空指针,若发生错误则返回NULL。
void *dlsym (void *handle, char *symbol)
dlerror
检查错误。如果任何函数出错,dlerror返回一个描述错误的字符串,再把错误的字符串置为NULL。
const char *dlerror (void);
dlclose
卸载共享库。确定不再需要某个共享对象后,关闭它以节省系统资源。
int dlclose (void *handle);