目录
1. 库的概念
库是一个二进制文件,包含的代码可被程序调用,常见的库有标准C库、数学库、线程库……
库有源码,可下载后编译;也可以直接安装二进制包。
库是事先编译好的,可以复用的代码。在OS上运行的程序基本上都要使用库。使用库可以提高开发效率。
注:Windows和Linux下库文件的格式不兼容
Linux下包含静态库和动态库两种。
2. 静态库
2.1 静态库的特点
- 编译(链接)时把静态库中相关代码复制到可执行文件
- 程序中已包含代码,运行时不再需要静态库
- 程序运行时无需加载库,运行速度更快
- 占用更多磁盘和内存空间
- 静态库升级后,程序需要重新编译链接
2.2 静态库的创建
2.2.1 编写函数
编写一个hello函数,去打印"hello world"。
#include <stdio.h>
int hello()
{
printf("hello world\n");
return 0;
}
2.2.2 编译生成目标文件
gcc -c hello.c -Wall
2.2.3 创建静态库
ar -rsv libhello.a hello.o
注意:
1 静态库名字要以lib开头,后缀名为.a
2 没有main函数的.c 文件不能生成可执行文件。
ar参数:
c | 禁止在创建库时产生的正常消息 |
r | 如果指定的文件已经存在于库中,则替换它 |
s | 无论 ar 命令是否修改了库内容都强制重新生成库符号表 |
v | 将建立新库的详细的逐个文件的描述写至标准输出 |
q | 将指定的文件添加到库的末尾 |
t | 将库的目录写至标准输出 |
2.2.4 查看库中符号信息
nm -a libhello.a
nm:显示指定文件中的符号信息
-a 显示所有符号
2.3 链接静态库
2.3.1 编写应用程序
#include <stdio.h>
void hello();
int main(int argc,char* argv[])
{
hello();
return 0;
}
2.3.2 编译并链接静态库
gcc -o test test.c -L. -lhello
-L 表示库所在的路径
-l 后面跟库的名称
2.3.3 执行应用程序
./test
可以看到应用程序已成功链接了我们编写的静态库,并执行打印了hello world。
3. 动态库
3.1 动态库的特点
- 编译(链接)时仅记录用到哪个动态库中的哪个符号,不复制动态库中相关代码
- 程序不包含库中代码,尺寸小
- 多个程序可共享同一个库
- 程序运行时需要加载库
- 库升级方便,无需重新编译程序
- 使用更加广泛
3.2 动态库的创建
3.2.1 编写函数
编写一个hello函数,去打印"hello world"。
#include <stdio.h>
void hello()
{
printf("hello world\n");
}
编写一个bye函数,去打印"bye"。
#include <stdio.h>
void bye()
{
printf("bye\n");
}
3.2.2 编译生成目标文件
gcc -c -fPIC hello.c bye.c -Wall
3.2.3 创建共享库
gcc -shared -o libcommon.so.1 hello.o bye.o
3.2.4 为共享库文件创建链接文件
ln -s libcommon.so.1 libcommon.so
符号链接文件命名规则:lib<库名>.so
3.2.5 编写应用程序
#include <stdio.h>
#include “common.h”
int main()
{
hello();
bye();
return 0;
}
3.2.6 编译并链接共享库
gcc -o test test.c -L. -lcommon
3.2.7 执行程序
./test
可以看到存在报错提示,
含义:可执行文件所使用的动态库找不到
解决办法:
- 把库拷贝到/usr/lib和/lib目录下
- 在LD_LIBRARY_PATH环境变量中添加库所在路径
- 添加/etc/ld.so.conf.d/*.conf文件,执行ldconfig刷新
3.2.8 添加共享库的加载路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
再去执行应用程序
./test
3.2.9 查看可执行文件所使用的动态库
ldd 你的可执行文件
4. 总结
本文介绍了库的概念,并介绍了linux系统下的两种库(静态库和动态库),此外对这两种库进行了特点的说明以及通过编写代码实现了两类库的应用。