库
什么是库:
库是一个二进制文件,包含的代码可用被程序调用。常见的库有标准C库、数学库、线程库。
调用库的方式有两种:
- 使用库的源码,下载后编译
- 直接安装库的二进制包
在Linux下,库存放在/lib 和 /usr/lib 目录下
静态库与动态库的区别:
- 静态库 .a:
静态库会在链接时将静态库中的相关代码复制到可执行文件中,即:可执行文件中包含了静态库,只需要这个可执行文件即可运行程序。
使用静态库生成的可执行文件,运行时不需要加载库(因为本身就包含了静态库的内容),运行速度更快。但因为每一个可执行文件中都复制了静态库的内容,所以会占用更多的磁盘和内存空间。
从上述描述中可以看到,可执行文件中的静态库是写死的,这代表静态库升级后,程序需要重新编译链接才可将升级后的静态库写入到可执行文件中。
- 动态库(共享库).so :
动态库在链接时仅仅将库中的符号复制到可执行文件中,即:可执行文件中只包含了链接,没有库本身,库和可执行文件都存在时,程序才可执行。
使用动态库生成的可执行文件,运行时需要加载库。因为可执行文件中不包含库源码,所以占用的空间少,库升级时也不用重新编译,同时多个程序也可以共享一个库。
使用静态库步骤
简易的步骤如下:
- 编写库源码,使用.o文件生成静态库.a
- 编写应用程序源码,编译时链接静态库
具体实现步骤如下:
1.1 创建.c文件,编写相关的函数实体。这里以简单的编写一个hello world为例。
1.2 将.c文件进行编译汇编。gcc -c hello.c -o hello.o
1.3 将.o文件生成静态库。ar -rsv libhello.a hello.o
具体ar命令使用、命名规则在补充章节。
1.4 查看静态库有哪个文件生成。ar -tv libhello.a
2.1 编写应用源码。这里就简单使用以下库里面的hello函数。
2.2 在编译汇编test.c时链接静态库。gcc test.c -L . -l hello -o test
这代表编译test.c是,在当前路径下寻找库(-L),库的名称为hello(-l),生成的可执行文件为test
注意:当2.2步骤完成后,可执行程序test中已经包含了静态库hello的全部代码,这时将可执行程序test或静态库hello随意移动,都不会产生影响,即:test与hello是两个独立的个体。
使用动态库步骤
简易的步骤如下:
具体实现步骤如下:
1.1 创建.c文件,编写相关的函数实体。这里以简单的编写一个hello world为例。
1.2 将.c文件进行编译汇编。gcc -c -fPIC hello.c -o hello.o
1.3 将.o文件生成动态库。gcc -shared hello.o -o libhello.so
2.1 编写应用源码。这里就简单使用以下库里面的hello函数。
2.2 在编译汇编test.c时链接静态库。gcc test.c -L . -l hello -o test
2.3 添加共享库的加载路径
方式1:将动态库libhello.so拷贝到/usr/lib 或 /lib目录下
这种方式不推荐,因为会把这两个目录搞的很乱。
方式2:在环境变量LD_LIBRARY_PATH中添加库所在路径,并将这个变量加入启动脚本中。
打开启动脚本:vi ~/.bashrc
执行启动脚本:source ~/.bashrc
补充
1、创建静态库命令 ar
参数含义:
- c:禁止在创建库产生正常的信息,即:只打印错误信息
- r:如果指定的文件已经存在于库中,则替换它
- s:强制重新生成库符号表
- v:打印建立新库的文件描述
- q:将指定的文件添加到库的末尾
- t:打印库的目录,即:查看静态库有哪个文件生成
静态库名称命名规则:
以lib开头,后面为库名,静态库以.a结尾。比如 libhello.a 这代表名为hello的静态库。
2、查看库中的符号表 nm
nm <.o文件> 查看库中的符号表
3、查看文件使用的动态库 ldd
ldd <可执行文件>