什么是库文件
1. 库文件是计算机上的一类文件,可以简单的把库文件看成一种代码的仓库,它提供给使用者一些可以直接拿来用的变量,函数或者类。
2. 库是一种特殊的程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。
3. 库文件有两种:静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接的阶段没有被复制到程序中,
4. 而是程序在运行时由系统动态加载到内存中供程序调用。
5. 库的好处:1.代码保密,2.方便部署和分发
静态库的制作
6. 命名规则
7. Linux: libxxx.a
lib: 前缀(固定)
xxx: 库的名字
.a : 后缀(固定)
windows: libxxx.lib
8. 静态库的制作
(1) gcc获得.o文件
gcc -c *.c
(2) 将.o文件打包,使用ar工具。(archive)
ar rcs libxxx.a xxx.o xxx.o
r - 将文件插入备存文件
c - 建立备存文件
s - 索引
制作的静态库一般只要.o文件,不包含头文件.h。因为在每个.c函数里面都包含了头文件。
例如现在有的源文件有下面所示图中的src里面的.c文件:
制作静态库的过程为:
ar rcs libcalc.a *.o
通过上述的命令,生成了calc的静态库。复制到lib文件夹里面去。
静态库的使用
9. 假设现在有下面的一些文件:
10.include文件夹是包含的是这些src函数的函数声明以及一些其他声明; lib文件夹包含的是这些src文件夹下面的原代码形成的静态文件
库;src文件夹里面就是一些源代码了;
//head.h里面的代码
//main函数的内容
12.通过命令成成可执行文件:
(1). gcc main.c -o app;
这时候会出现下面的错误信息:
main.c:2:18: fatal error: head.h: No such file or directory;
出现上述的信息是因为一般寻找头文件.h是在1当前文件夹下面,而我目前的main函数的位置和head.h的位置是不一样的。
为了解决这个问题,引入了【gcc -I 文件夹】命令的使用。-I是指定头文件处在的位置的。
(2). gcc main.c -I ./include -o app
这时候出现了以下的错误信息:
/tmp/ccUnTREq.o: In function `main':
main.c:(.text+0x38): undefined reference to `add'
main.c:(.text+0x58): undefined reference to `subtract'
main.c:(.text+0x78): undefined reference to `multiply'
main.c:(.text+0x98): undefined reference to `divide'
collect2: error: ld returned 1 exit status
这是因为上面指定了头文件中的函数没有找到,这时候就需要指定库文件了,通过 【-l 库名字】的方式加载库文件。
(3). gcc main.c -I ./include -l calc -o app
然而这时候出现了以下的错误信息:
usr/bin/ld: cannot find -lcalc
collect2: error: ld returned 1 exit status
是找不到这个库的所处的位置,这时候就需要通过【-L 库的路径】来指定库的路劲;
(4). gcc main.c -I ./include -l calc -L ./lib -o app
这时候就生成了可执行文件app了;
.
├── app
├── include
│ └── head.h
├── lib
│ └── libcalc.a
├── main.c
└── src
├── add.c
├── div.c
├── mult.c
└── sub.c
动态库的制作
1. 命名规则:
2. Linux: libxxx.so
3. lib: 前缀(固定)
4. xxx: 库的名字,自己起
5. .so: 后缀(固定)
6. windows: libxxx.dll
7. 动态库的制作:
8. gcc 得到.o文件,得到和位置无关的代码
9. gcc -c -fpic/-fPIC a.c b.c
10. 得到动态库
11. gcc -shared a.o b.o -o libcalc.so
12.
动态库的使用
13. 整个的文件树如下所示:
.
├── app
├── include
│ └── head.h
├── lib
│ └── libcalc.so
├── main.c
└── src
├── add.c
├── div.c
├── mult.c
└── sub.c
14. 通过命令 gcc main.c -o app -I ./include/ -l calc -L ./lib 生成了可执行文件app;
15. 在执行./app的时候出现了如下的错误信息:
16. ./app: error while loading shared libraries: libcalc.so: cannot open shared object file:
17. No such file or directory
18. 上面的意思就是在执行app文件的时候无法打开下载共享库文件libcalc.so。
19. 这就需要了解其工作原理了。
工作原理
20. 静态库:GCC链接时,会把静态库中的代码打包到可执行程序中。
21. 动态库:GCC进行链接时,不会把动态库中的代码打包到可执行程序中。意思就是在进行链接的时候,需要将动态库加载进来才行。
22. 程序启动之后,动态库会被动态加载到内存中,通过ldd(list dynamic dependencies)命令检查动态库依赖关系。
23. 例如:ldd app
24. [root@localhost library]# ldd app
linux-vdso.so.1 => (0x00007ffdbbcaa000)
libcalc.so => not found(没找到)
libc.so.6 => /lib64/libc.so.6 (0x00007f8b525fd000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8b529cb000)
25. 如何定位共享文件库呢?
26. 当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。
27. 对于elf格式的可执行程序,是由ld-1inux.so来完成的,它先后搜索e1f文件的DT_RPATH段一>
28. 环境变量LD_LIBRARY_PATH -> /etc/1d.so.cache文件列表 -> /1ib/,/usr/lib目录找到库文件后将其载入内存。
解决动态库路径的问题
30. (1)在LD_LIBRARY_PATH添加库的路劲:
31. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/牛客/lesson6/library/lib
32. 上面的命令中:后面的就是我们添加的路径。但是这是在终端中进行配置,关掉终端之后就没了。所以就需要永久性质的添加库文件的路径。
33. 有两种方式的配置:用户级别的配置和系统级别的配置。
34. a):用户级别的配置就是在用户级别的家目录下的.bashrc文件里面最后一行新添加上面的export命令;添加完之后进行source .bashrc
35. b):系统级别的话也可以在家目录下的.bashrc文件中添加动态库路径;也可以在/etc/profile文件中添加。
36.
37. (2) 修改/etc/ld.so.cache文件列表
38. 打开/etc /ld.so.cache文件是我们看不懂的乱码二进制状态,我们不能直接修改它,需要间接修改它,所以直接打
39. 开/etc/ld.so.conf文件,直接在后面添加库的路径。
39.
40. (3)其他的方法不建议使用