目录
动静态库的简单理解
其实我们平常写一些C或C++的代码的时候,在链接过程都会用到动静态库,因为一些库函数代码我们是不用写的(比如输入输出函数),我们只需要包个头文件就可以用,头文件中只存函数的声明,动静态库中才是函数的实现代码编译后形成的目标文件,这些库和我们的编译好的代码一起链接后才会形成可执行程序
那么我们用到的库分为两种,静态库 和动态库 ;链接方式于是就分为了动态链接 和静态链接
动态链接是库就一份,可执行程序中只存有库函数的地址(实际上就是只知道要调用哪个库),要调用的话就去内存中找到这个库
静态链接则是直接把库拷贝到可执行程序中,这就使可执行程序在运行时不需要库了
因为动静态库的差异,它们是有各自的优缺点的
动态库:
优点:比较节省资源,不会出现太多的重复代码(这里的资源可不仅仅指的是磁盘资源,还有运行时的内存资源,传输时的网络资源)
缺点:对库的依赖性强,一旦少了这个库,不仅用到这个库的目标文件无法链接成可执行程序,并且用到这个库的可执行程序也无法运行
静态库:
优点:不依赖库,同类型平台都可以运行使用
缺点:可执行程序体积比较大,比较浪费资源
动静态库在不同的操作系统下后缀也是不一样的
|-----|-------|---------|
| 库 | Linux | Windows |
| 动态库 | .so | .dll |
| 静态库 | .a | .lib |
我们在gcc/g++下是默认使用动态链接的,有一个命令可以查看文件依赖的库 (ldd+文件名 ),还有一个命令可以查看文件的具体信息 (file+文件名),当然了,我们如果想使用静态链接的话也是有命令的,gcc后加选项-static,我们下面来试验一下两种链接方式有什么区别
有的云服务器是默认没有静态库的,我们要用yum安装一下静态库
cpp
yum install -y glibc-static libstdc++-static
我们安装完之后可以在下面的路径看到,安装的就是libc.a
这是我将test.c用两种链接方式形成的可执行程序,可以看到静态链接形成的可执行程序是比较大的,因为它并不需要依赖别的文件了
也可以看到动态链接确实是需要依赖一些库的,而静态链接不需要
也可以看到,画起来的部分确实写得是静态链接,而上面写的是动态链接
并且我们要知道库的真实名字是去掉前面的去掉前面的lib和后面的后缀,比如
就是libc.a ,其实真实名字就是c
就是libldap-2.4.so.2.10.7 ,真实名字就是ldap-2.4
自己简单制作动静态库
静态库的制作
因为静态库只有在链接的时候使用,而动态库在链接和运行的时候都需要使用,所以对于静态库的制作和制作中出现的一些问题是动态库制作过程中问题的子集,所以我们先简单的来制作一下静态库
我们先来简单的理解一下有关库的问题,我们写库的人一般写多组头文件和源代码文件 ,我们一般不想把源代码透露出去,所以让源代码文件先进行编译(预处理,编译,汇编)环节形成多个目标文件 ,我们当然可以把头文件(含有函数的声明,即告诉用库的人如何使用)和目标文件全给用库的人,但是文件太多容易丢失,所以要将目标文件打包成库,形成一个库文件在给用户使用。那么我们就来简单的实现一下这个过程:
比如我现在已经写好了头文件和源代码文件,然后编译一下源文件
现在我就可以对于目标文件进行打包了,用下面的创建静态库的命令,在这个命令中,r表示插入新的成员,c表示创建新的库文件
有了这个库文件,我们就可以使用了,比如我在这个目录下创建一个使用这个库的用户,用户创建一个main.c使用add和sub函数,我如果只把头文件拷贝到这个用户的目录下它还是无法编译的,因为它找不到静态库
所以我们需要通过如下的命令指明静态库的路径和名称,其中-L选项指定库文件所在的路径,-l选项指定要链接的库文件名称(省略lib前缀和.a后缀)
我们平常在用静态链接的时候不用指明路径和名称是因为源文件包含了系统自带的头文件,所以编译器会默认去固定的存放静态库的目录中查找。
动态库的制作
动态库的制作也是先生成目标文件,然后打包目标文件成为动态库,但是指令会有所不同
这里的fPIC选项是生成位置无关码,这意味着它不依赖于特定的虚拟内存地址,这样生成的代码会使用相对地址,避免绝对地址的使用,这意味着可以在不同的虚拟内存地址空间中加载和执行,使动态库更加灵活和可移植
shared表示生成共享库格式,也就是指明要生成动态库
然后我们下面就像创建静态库时那么做,生成了一个可执行文件
这个可执行文件如果时静态链接就已经可以运行了,但是动态链接不可以
因为前边说过动态链接的话编译和运行阶段都需要动态库(编译是gcc需要,运行是操作系统需要),现在运行的时候它找不到动态库
我们有这么几种方法:
1.直接将自己写的库安装(拷贝)到系统中
2.有这样一个环境变量
它里面放的就是系统运行程序时,动态库查找的辅助路径,所以我们可以把自制的动态库的路径添加到这个环境变量中
3.通过建立软链接的方式,就是将默认路径下创建一个与自制的动态库进行软链接的文件
动态库加载到内存之后,会被用到这个动态库的进程映射到进程地址空间的共享区 中,所以一个动态库可以映射到多个进程中,其实每个可执行程序在开头都会表明需要哪个动态库,让操作系统帮忙加载;而静态库是直接拷贝到可执行程序中。进程如何知道它的地址空间应该如何分配呢?其实这些信息也都存在于可执行程序中,所以地址空间是由操作系统和编译器共同配合完成的。