目录
认识动静态库
如何制作动静态库?
静态库
动态库
使用库
使用静态库
使用动态库
为什么动态链接是如此呢?
认识动静态库
我们在使用标准库的时候,需要有系统的头文件和系统的库文件,这个库文件是什么呢?
当.cpp文件被编译成.o文件时,将自己的.o文件和头文件可以直接给别人就可以使用,这个.o文件其实就类似于库文件,库文件的本质就是一系列.o文件的打包。库文件分成两种,一种是动态库,一种是静态库。
如何制作动静态库?
静态库
比如说要把下面四个文件做成静态库:
用makefile一键构建
1.首先将所有的源文件.c 使用gcc的 -c选项生成 .o文件
2.使用ar -rc命令打包文件
ar其实就是一个打包软件
其选项含义:
-r(replace)是如果目标文件有更新了,就替换原来的
-c(create)是创建静态库文件
-t 列出文件
-v显示文件的详细信息
注意:静态库的库名格式是以lib开头.a结尾
3.为了方便给他人使用,将库发布,其实就是进一步整理,使用makefile一次执行多行命令,建立库目录和头文件目录,然后将.a库文件和.h头文件分别放入即可。
整体makefile就像这样,以后就能一键生成静态库了:
mylib=libmylib.a #makefile下可以定义变量var,后面用$(var)使用
$(mylib):printTime.o add.o
ar -rc -o $(mylib) $^
cc=g++
%.o:%.cc #%.o表示所有.o文件,%.cc表示所有.cc文件, $<和$^都表示所有的依赖目标集
$(cc) -c $< -std=c++11
.PHONY:clean
clean:
rm -rf $(mylib) ./*.o ./*.a mylib
.PHONY:output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp ./*.h mylib/include
cp ./*.a mylib/lib
比如 一键生成的静态库,方便使用:
动态库
制作动态库同理,前两步略有不同。
1.将所有的源文件.c 使用gcc的 -c选项生成 .o文件,还要带上-fPIC表示产生与位置无关码的目标文件,因为静态链接是拷贝代码到调用处,具有绝对地址,而动态库是动态链接的可以理解为没有绝对地址。
2.使用gcc的 -shared选项将所有的.o文件生成.so动态库即可。
3.发布,同上
于是整体makefile就像这样,以后就能一键生成动态库了:
mylib=libmylib.so #makefile下可以定义变量var,后面用$(var)使用
$(mylib):printTime.o add.o
g++ -shared -o $(mylib) $^
cc=g++
%.o:%.cc #%.o表示所有.o文件,%.cc表示所有.cc文件, $<和$^都表示所有的依赖目标集
$(cc) -fPIC -c $< -std=c++11
.PHONY:clean
clean:
rm -rf $(mylib) ./*.o ./*.so mylib
.PHONY:output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp ./*.h mylib/include
cp ./*.so mylib/lib
那么如何使用动静态库呢?
使用库
比如当前文件夹下只有刚才打包好的mylib文件夹,当前的.cc文件如何使用库呢?
使用静态库
因为当前文件夹下只有刚才打包好的mylib文件夹,所以编译直接报错
可以在“”中放入头文件的具体路径,比如:
或者将头文件放入系统头文件/usr/include/目录下系统头文件(usr/include/)路径,(注意需要root权限)比如:
gcc编译的时候gcc就会去在系统头文件目录下去查找
但是库文件未安装,需要将库安装到系统库文件目录/lib64/下
但是gcc还是不认识库和头文件,因为默认gcc中是没有的,
需要以下步骤:
指定头文件搜索路径 :-I 头文件搜索路径
指定库文件搜索路径:-L 库文件搜索路径
指定链接的库文件:-l 库名(去掉lib和.a)
注意:选项与路径或库名可不加空格
也就是这样:
于是编译就通过了,因为倘若我们的代码不成熟,拷贝进系统库中,会污染库,所以不建议拷贝入系统的库文件下,可以直接指定我们的相应的路径,也能编译通过,比如:
使用动态库
方法与使用静态库一样,同上带上三个选项-I -L -l 告诉编译器相关路径,但是生成的程序仍然不知道依赖的库,除非在.so当当前文件夹下面,使用静态库没有这个问题,因为可执行程序已经拷贝了代码,不依赖库。
所所以运行程序时就会报错加载动态库错误:
使用命令ldd就可以查看到动态链接了:
需要让进程找到动态库,主要有三种方法:
1.拷贝动态库到系统库路径下:
2.导入环境变量,程序运行时会在环境变量中查找自己需要的动态库路径
(xshell退出环境变量会失效)
在环境变量LD_LIBRARY_PATH中添加动态库的路径 ,比如:
3.系统配置文件来做
在/etc/ld.so.conf.d下添加.conf文件,文件内容就是我们的动态库的绝对路径,
再使用sudo ldconfig命令让配置文件生效即可
4.其他方法:
在/lib64/下建立我们的动态库的软链接
如果系统库路径下有我们的软连接,编译选项只要-I 和 -l即可。
链接成功之后,把当前文件的软链接删掉,用ldd查看a.out的动态链接情况:
为什么动态链接是如此呢?
因为程序运行时,有一部分代码需要跳转到动态库中运行,OS将代码加载到物理内存,页表把内存共享区与物理内存建立映射,运行代码时跳转到共享区即可,其他进程也使用这个动态库的时候只要页表建立映射即可,在物理内存动态库只有一份 ,所以进程在运行时如果要加载动态库,需要先找到动态库。而使用静态库时,静态库的代码在代码区已经拷贝了一份不需要再去查找静态库代码。