7.动静态库
Nevermore 2022-06-03 OS
# 1. 动静态库的查看
Windows中的动态库文件以
.dll
为后缀名、静态库以.lib
为后缀;而Linux动态库文件后缀为.so
、静态库为.a
库的真名:去掉
lib
前缀,去掉.a
\.so
后缀,剩下的就是库名。例如libc-2.17.so
,库的真名就是c-2.17
ldd
查看可执行程序包含的动态库。动态库系统中默认包含,因为许多shell程序都依赖动态库运行。程序在链接时默认使用动态库。
[test@VM-12-4-centos first]$ ldd main
linux-vdso.so.1 => (0x00007ffebedab000)
/$LIB/libonion.so => /lib64/libonion.so (0x00007f1bbd2e5000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1bbcdfe000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f1bbcbfa000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1bbd1cc000)
[test@VM-12-4-centos first]$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=d8c679773c4e5c5c3972a1a5ad579065387333ad, not stripped
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 若将源文件以静态(
-static
)的方式链接,则会产生一个静态的可执行文件;使用静态链接需要安装相依赖的静态库。
[test@VM-12-4-centos first]$ gcc main.c -o main_static -static
[test@VM-12-4-centos first]$ file main_static
main_static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=6de48a06365f646b6f73ebb0b9fb5d1863a5f0b9, not stripped
1
2
3
2
3
# 2. 动静态库的制作和使用
# 2.1 源文件直接使用,不生成库
[test@VM-12-4-centos first]$ ls && ls mylib/
main.c Makefile mylib
PrintHello.c PrintHello.h PrintWorld.c PrintWorld.h
1
2
3
2
3
//PrintHello.h
#include <stdio.h>
extern void PrintHello();
//PrintHello.c
#include "PrintHello.h"
void PrintHello(){
printf("hello\n");
}
//PrintWorld.h
#include <stdio.h>
extern void PrintWorld();
//PrintWorld.c
#include "PrintWorld.h"
void PrintWorld(){
printf("world\n");
}
//main.c
#include "./mylib/PrintHello.h"
#include "./mylib/PrintWorld.h"
int main()
{
PrintHello();
PrintWorld();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# src = main.c ./mylib/PrintHello.c ...
src = ./mylib/%.c
obj = main.o PrintHello.o PrintWorld.o # 不加路径,当前目录下生成
# mytest:%.o # %通配符,将所有.o结尾的文件展开
main:$(obj)
gcc -o $@ $^
%.o:%.c # %c 依赖所有 .c (当前目录)
gcc -c $<
%.o:$(src)
gcc -c $< # < :将.c内容展开依次编译,没有-o指明,则生成同名的.o文件
.PHONY:clean
clean:
rm -rf *.o main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
运行结果:
[test@VM-12-4-centos first]$ make
gcc -c main.c
gcc -c mylib/PrintHello.c
gcc -c mylib/PrintWorld.c
gcc -o main main.o PrintHello.o PrintWorld.o
[test@VM-12-4-centos first]$ ls
main main.c main.o Makefile mylib PrintHello.o PrintWorld.o
[test@VM-12-4-centos first]$ ./main
hello
world
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 2.2 生成静态库
# 2.2.1 静态库的生成
将所有源文件生成.o
然后打包即可得到静态库。Makefile如下:
liba.a:PrintHello.o PrintWorld.o
ar -rc $@ $^ # ar 归档命令(打包) r(replace) c(create)
%.o:%.c
gcc -c $<
.PHONY:clean
clean:
rm -rf *.o *.a
.PHONY:output
output:
mkdir output
cp -rf *.h output
cp liba.a output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
操作和结果:
[test@VM-12-4-centos mylib]$ ls
Makefile PrintHello.c PrintHello.h PrintWorld.c PrintWorld.h
[test@VM-12-4-centos mylib]$ make
gcc -c PrintHello.c
gcc -c PrintWorld.c
ar -rc liba.a PrintHello.o PrintWorld.o # ar 归档命令(打包) r(replace) c(create)
[test@VM-12-4-centos mylib]$ ls
liba.a Makefile PrintHello.c PrintHello.h PrintHello.o PrintWorld.c PrintWorld.h PrintWorld.o
[test@VM-12-4-centos mylib]$ make output # 发布
mkdir output
cp -rf *.h output
cp liba.a output
[test@VM-12-4-centos mylib]$ make clean
rm -rf *.o *.a
[test@VM-12-4-centos mylib]$ ls
Makefile output PrintHello.c PrintHello.h PrintWorld.c PrintWorld.h
[test@VM-12-4-centos mylib]$ cd output/
[test@VM-12-4-centos output]$ ls
liba.a PrintHello.h PrintWorld.h
[test@VM-12-4-centos output]$ ar -tv liba.a # 查看库依赖的.o
rw-rw-r-- 1001/1001 1496 Jun 3 23:43 2022 PrintHello.o
rw-rw-r-- 1001/1001 1496 Jun 3 23:43 2022 PrintWorld.o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2.2.2 静态库的使用
#include "./output/PrintHello.h"
#include "./output/PrintWorld.h"
int main()
{
PrintHello();
PrintWorld();
return 0;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
main:main.c
gcc -o $@ $^ -I./output -L./output -l a # -I 头文件路径; -L 库文件路径; -l 库名称
.PHONY:clean
clean:
rm -rf *.o main
# path = $(shell pwd) # 使用绝对路径的写法
# main:main.c
# gcc -o $@ $^ -I$(path)/output -L$(path)/output -la
# .PHONY:clean
# clean:
# rm -rf *.o main
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
gcc默认可以在当前目录下查找头文件和库,若包含子目录需指定:
-I
指定头文件查找路径,选项和名字之间可以不带空格
-L
指定自定义库搜索路径
-l
指定链接库的名字(libc.so -> 名字变为c :去掉开头的lib
和.
后的内容)
运行结果:
[test@VM-12-4-centos first]$ ls
main.c Makefile mylib output
[test@VM-12-4-centos first]$ make
gcc -o main main.c -I./output -L./output -l a
[test@VM-12-4-centos first]$ ls
main main.c Makefile mylib output
[test@VM-12-4-centos first]$ ./main
hello
world
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2.3 生成动态库
# 2.3.1 动态库的生成
liba.so:PrintHello.o PrintWorld.o
gcc -shared -o $@ $^
%.o:%.c
gcc -fPIC -c $< # 添加-fPIC选项。
.PHONY:clean
clean:
rm -rf *.o *.so output
.PHONY:output
output:
mkdir output
cp -rf *.h output
cp liba.so output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
操作和结果:
[test@VM-12-4-centos mylib]$ ls
Makefile PrintHello.c PrintHello.h PrintWorld.c PrintWorld.h
[test@VM-12-4-centos mylib]$ make
gcc -fPIC -c PrintHello.c
gcc -fPIC -c PrintWorld.c
gcc -shared -o liba.so PrintHello.o PrintWorld.o
[test@VM-12-4-centos mylib]$ make output
mkdir output
cp -rf *.h output
cp liba.so output
[test@VM-12-4-centos mylib]$ ls
liba.so Makefile output PrintHello.c PrintHello.h PrintHello.o PrintWorld.c PrintWorld.h PrintWorld.o
[test@VM-12-4-centos mylib]$ cd output/
[test@VM-12-4-centos output]$ ls
liba.so PrintHello.h PrintWorld.h
[test@VM-12-4-centos mylib]$ cp output -r ..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2.3.2 动态库的使用
代码和makefile与2.2.2 中一样,注意要将动态库加载到内存才可以让使用动态库的程序正常运行。直接操作:
[test@VM-12-4-centos first]$ make
gcc -o main main.c -I./output -L./output -l a
[test@VM-12-4-centos first]$ ls
main main.c Makefile mylib output
[test@VM-12-4-centos first]$ ./main
./main: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory # 运行时需要让系统知道动态库的位置,将自己的库加载到内存
1
2
3
4
5
6
2
3
4
5
6
运行时让告知系统库路径:
- 修改
LD_LIBRARY_PATH
环境变量中关于动态库的路径
[test@VM-12-4-centos first]$ echo $LD_LIBRARY_PATH [test@VM-12-4-centos first]$ ls main main.c Makefile mylib output [test@VM-12-4-centos first]$ cd output/ [test@VM-12-4-centos output]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD # 只在本bash进程可用。可以添加到bashrc [test@VM-12-4-centos output]$ echo $LD_LIBRARY_PATH :/home/test/process/Fork/first/output [test@VM-12-4-centos output]$ cd .. [test@VM-12-4-centos first]$ ls main main.c Makefile mylib output [test@VM-12-4-centos first]$ ldd main linux-vdso.so.1 => (0x00007ffdca650000) /$LIB/libonion.so => /lib64/libonion.so (0x00007f1f5c9ac000) liba.so => /home/test/process/Fork/first/output/liba.so (0x00007f1f5c691000) #此时链接到了自己的库 libc.so.6 => /lib64/libc.so.6 (0x00007f1f5c2c3000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f1f5c0bf000) /lib64/ld-linux-x86-64.so.2 (0x00007f1f5c893000) [test@VM-12-4-centos first]$ ./main hello world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22- 也可在
/etc/ld.so.conf.d/
添加配置文件,这里命名成mylib.conf
,文件内容即为库的路径。需要root。
[root@VM-12-4-centos output]# echo /home/test/process/Fork/first/output > /etc/ld.so.conf.d/mylib.conf [root@VM-12-4-centos output]# ls /etc/ld.so.conf.d/mylib.conf -l -rw-r--r-- 1 root root 64 Jun 4 01:36 /etc/ld.so.conf.d/mylib.conf [root@VM-12-4-centos output]# cat /etc/ld.so.conf.d/mylib.conf /home/test/process/Fork/first/output [root@VM-12-4-centos output]# ls liba.so PrintHello.h PrintWorld.h [root@VM-12-4-centos output]# ldconfig # 在该库目录下执行,用来更新缓存 [test@VM-12-4-centos first]$ ./main hello world
1
2
3
4
5
6
7
8
9
10
11
12- 修改