命名(习惯 ):
静态库: .lib/.a 动态库.dll/.so
静态库的命名一般分为三个部分:
前缀:lib
库名称:自定义即可, 如test
后缀:.a
共享库的命名一般分为三个部分:
前缀:lib
库名称:自己定义即可, 如test
后缀:.so
库制作完成后, 如何给用户使用
头文件—包含了库函数的声明
库文件—包含了库函数的代码实现
静态库的制作:
1 将.c文件编译成.o文件
gcc -c fun1.c fun2.c
2 使用ar命令将.o文件打包成.a文件
ar rcs libtest1.a fun1.o fun2.o // 一定要加.a 后缀,否则识别不到
r:更新
c:创建
s:建立索引
静态库的使用:
-I 指定头文件
-L: 指定库文件所在目录
-l: 指定库文件 libtest1.a 对应的是 test1
1 main.c与head.h和libtest1.a在同一级目录的情况
gcc -o main1 main.c -I./ -L./ -ltest1
2 main.c与head.h和libtest1.a在不同一级目录的情况
gcc -o main1 main.c -I./include -L./lib -ltest1
动态库的制作:
1 将.c文件编译成.o文件
gcc -fpic -c fun1.c fun2.c
2 使用gcc将.o文件编译成库文件
gcc -shared fun1.o fun2.o -o libtest2.so
动态库的使用:
gcc -o main2 main.c -I./include -L./lib -ltest2
动态库文件在编译的时候, 连接器需要使用参数-L找到库文件所在的路径;
在执行的时候, 是加载器ldd根据动态库的路径进行加载的, 与编译的时候用的-L指定的路径无关.
最常用的解决办法:将LD_LIBRARY_PATH环境变量加到用户级别的配置文件~/.bashrc中,
然后生效(. ~/.bashrc source ~/.bashrc 退出终端然后再登录)
head.h
void fun1();
void fun2();
fun1.c
#include <stdio.h>
void fun1()
{
printf("this is fun1\n");
}
fun2.c
#include <stdio.h>
void fun2()
{
printf("this is fun2\n");
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "head.h" // 头文件添加的时机是,谁调用谁加头文件,预处理的时候会将其对应的实现展开
int main(int argc, char *argv[])
{
printf("this is main!\n");
fun1();
fun2();
return 0;
}
动态库执行时候报错解决
分析为什么在执行的时候找不到libtest2.so库
当系统加载可执行代码时候, 能够知道其所依赖的库的名字, 但是还需要知道所依赖的库的绝对路径。此时就需要系统动态载入器(dynamic linker/loader)。
ldd命令可以查看可执行文件依赖的库文件, 执行ldd main2, 可以发现libtest2.so找不到.
对于elf格式的可执行程序,是由ld-linux.so*来完成的, 它先后搜索elf文件的 DT_RPATH段 — 环境变量LD_LIBRARY_PATH — /etc/ld.so.cache文件列表 — /lib/, /usr/lib目录找到库文件后将其载入内存。
使用file命令可以查看文件的类型: file main2
如何让系统找到共享库
- 拷贝自己制作的共享库到/lib或者/usr/lib
- 临时设置LD_LIBRARY_PATH:
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径
- 永久设置, 把export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径, 设置到∼/.bashrc文件或者/etc/profile文件中
- 将其添加到 /etc/ld.so.cache文件中
编辑/etc/ld.so.conf文件, 加入库文件所在目录的路径
运行sudo ldconfig -v, 该命令会重建/etc/ld.so.cache文件
解决了库的路径问题之后, 再次ldd命令可以查看可执行文件依赖的库文件, ldd main2: