概览
1. 测试代码
测试程序:
//////////////////test.h///////////////////
#ifndef __TEST_H__
#define __TEST_H__
#include <stdio.h>
#include <unistd.h>
void func();//声明函数
#endif
//////////////////test.c///////////////////
#include "test.h"
//作为库文件使用 编译动态库不能出现main函数
void func() //实现
{
printf("I am dynamic\n"); //简单的打印
}
//////////////////main.c///////////////////
#include "test.h"
int main()
{
func();//使用
return 0;
}
2. 动态库与静态库初识
- 静态库(.a): 程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
- 动态库(.so): 程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
- 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
3. 动态库
3.1 库搜索路径
- 从左到右搜索 -L 指定的目录
- 由环境变量指定的目录(LD_LIBRARY_PATH),该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径。
- 由系统指定的目录
- /usr/lib
- /usr/local/lib
运行时动态库的搜索路径的先后顺序是:
- 编译目标代码时指定的动态库搜索路径
- 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
- 配置文件/etc/ld.so.conf中指定的动态库搜索路径
- 默认的动态库搜索路径/usr/lib和/usr/local/lib
3.1 生成动态库
- gcc / g++
- -shared :表示生成共享库格式
- -fPIC:产生位置无关码 (position independent code)
- -o 后面跟生成的动态库的名字
前缀:lib
后缀:.so
libfunc.so ==> func 称之为动态库的名字
示例:
[test@localhost dynamic]$ ls
main.c test.c test.h
[test@localhost dynamic]$ gcc -shared -fPIC test.c -o libfunc.so
[test@localhost dynamic]$ ls
libfunc.so main.c test.c test.h
3.2 使用动态库
编译可执行程序的时候,一定要告诉编译器,我们链接的动态库是哪个
选项:
- -L [path] —— 指定链接动态库所在的路径
- -l [库的名称(去掉前缀和后缀的)] —— 链接动态库
输出结果:
[test@localhost dynamic]$ gcc main.c -o main -L . -l func
[test@localhost dynamic]$ ls
libfunc.so main main.c test.c test.h
[test@localhost dynamic]$ ./main
I am dynamic
3.3 查看当前程序依赖的动态库
- 命令:ldd [可执行程序] —— 查看当前程序依赖的动态库文件
3.4 查看文件属性
- 命令:file [可执行程序] —— 查看文件的属性
3.5 移动或删掉动态库
可执行文件是依赖这个动态库的,那么删掉或着移动动态库文件,程序是不能运行的。
可以通过修改环境变量LD_LIBRARY_PATH,指定除了文件默认搜索路径以外的路径。像上面这种.so动态库文件没有在缺省目录下 /usr/local/lib 和/usr/lib,那么就需要指定环境变量
但是,这样设定的环境变量不是永久生效的,重新打开一个终端,照样是不可以运行的
永久性添加:
因为上面的方法是临时设置环境变量 LD_LIBRARY_PATH ,重启或打开新的 Shell 之后,一切设置将不复存在。可以将该 LD_LIBRARY_PATH 的 export 语句写到系统文件中,例如:~/.bash_profile
最后使配置生效,重新打开终端,就可以运行了。
source ~/.bash_profile
4. 静态库
4.1 生成静态库
- 前缀:lib
- 后缀:.a
libfunc.a ==> func就是静态库的名字 - ar -rc lib[名字].a 依赖的文件
注意:依赖文件不是源文件,而是gcc -c 以后生成的.o 目标文件
示例:
[test@localhost static]$ ls
main.c test.c test.h
#生成静态库需要的目标文件
[test@localhost static]$ gcc -c test.c -o test.o
[test@localhost static]$ ls
main.c test.c test.h test.o
#生成静态库
# ar 是归档工具,rc表示(replace and create)
[test@localhost static]$ ar -rc libfunc.a test.o
[test@localhost static]$ ls
libfunc.a main.c test.c test.h test.o
#查看静态库的目录列表
[test@localhost static]$ ar -tv libfunc.a
rw-rw-r-- 1001/1001 1496 Apr 16 16:01 2021 test.o
# t:列出静态库中的目录列表
# v:verbose 详细信息
4.2 使用静态库
[test@localhost static]$ gcc main.c -o main -L . -l func
[test@localhost static]$ ls
libfunc.a main main.c test.c test.h test.o
[test@localhost static]$ ./main
I am static
再次查看文件属性以及依赖的库:
使用静态链接静态库:
gcc -static main.c -o main -L . -l func
再次查看文件属性以及依赖的库:
4.3 移动或删掉静态库
和动态库不同,在测试目标文件生成后,将静态库删掉或者移动,程序可以照样运行
5. 使用外部库(延伸)
系统中其实有很多库,它们通常由一组互相关联的用来完成某项常见工作的函数构成。
代码:
#include <math.h>
#include <stdio.h>
int main()
{
double x = pow(2.0, 3.0);
printf("The cubed is %f\n", x);
return 0;
}
//输出结果:
The cubed is 8.000000
链接外部库:
# -lm 表示要链接libm.so或者libm.a 库文件,即 m库
gcc calc.c -o calc -lm
查看文件属性以及依赖的库: