目录
我们之前用过库吗?是的,我们之前用过C/C++的标准库,比如strerror、strstr、strcpy,以及STL中的list、vector、stack、map、set,但是我们在用这些库的时候好像只是调用,并没有关心过怎么实现,我们自己写的二进制文件里,写的只是调用,那里面要不要有它们的实现呢?是一定要的!要不然文件都没有办法跑起来!但是它们的实现我们也没有见过啊,其实,它们的实现在我们的库中,比如,我们有下面一段代码:
我们并没有实现strcpy和printf, 但是在编译时通过gcc编译器链接了库,
我们可以通过ldd去找a.out所依赖的库:
框里的其实就是传说中的C语言标准库,那我们再打开一下这个库看一下:
这是一个软链接,链接了C语言的标准库,
这就是所,程序要运行起来,要有两个东西,一个是a.out,另一个是真正的库文件,C++也是类似。
在Linux中,以.so结尾的是动态库,以.a结尾的是静态库,(windows中以.dll结尾的是动态库,以.lib结尾的是静态库)。
静态库
头文件是一个手册,提供函数的声明,告诉用户怎么用;.o提供实现,我们只需要补上一个main函数,调用头文件提供的方法,然后和.o进行链接,就能形成可执行。
我们可以通过ar指令将所有.o文件打包:
ar -rc libmyc.a *.o
rc:replace and create
这就会形成libmyc.a文件。静态库
说到现在,我们可以说,所谓库文件,本质上就是把.o文件打包。
为什么要有库文件呢?提高开发效率!
那么,我们在编译时怎么使用我们自己写的头文件及其库文件呢?
gcc main.c -I ./mylib/include -L ./mylib/lib -lmyc
动态库
上面讲了如何生成静态库,那么怎么生成动态库呢?
在原来的基础上加上 -fPIC 即可,就可以生成mymath.o文件,由于动态库很常用,可以直接用gcc指令就可以生成:
生成的libmyc.so就是动态库。gcc在不使用static选项的时候,默认使用动态库。
所谓库文件,本质就是把.o打包,使用-fPIC指令。用gcc、g++ -shared指令可以生成动态库.so文件。
我们发现,当我们编译main.c时,指定头文件和库文件了,可执行程序仍不能找到要链接的库文件,,这是因为我们只告诉给了gcc/g++编译器,没有告诉操作系统!!!当形成了a.out后,往后的工作就和编译器无关了。因为动态库要在程序运行的时候,要找到动态库加载并运行!那为啥静态库没有这个问题呢??因为编译期间,已经将库中代码拷贝到我们的可执行程序内部了,加载和库就没有关系了!操作系统绝对不知道你指定的库文件,里面的文件多了去了,怎么知道你指定目录下的哪个文件呢??那怎么让可执行程序找到要链接的动态库呢?系统在运行期间会自动帮我们去找动态库,默认查找路径是/lib64,为了让可执行程序找到要链接的动态库,有几种方法:
1.把动态库拷贝到/lib64下,安装到系统
而且,在把动态库拷贝到/lib64下后,并没有重新编译mian.c,还是之前的a.out,说明可执行程序和动态库之间是松耦合的关系。但是,我们不想用这种方式来解决问题。删除刚才加进来的动态库,
2.在/lib64下建立动态库的软链接
这样就可以找到我的动态库,并且可以正常运行。
3.命令行导入环境变量,在环境变量LD_LIBRARY_PATH中添加路径
先删掉之间/lib64下建立的软链接,
我们现在既不想把动态库拷贝到lib64里,又不想在lib64里建立软链接。其实,在系统中还存在一个环境变量LD_LIBRARY_PATH,查看一下这个环境变量:
echo $LD_LIBRARY_PATH
所以,为了让a.out找到对应的动态库,我们可以添加路径:
有了这个路径之后,我们就可以执行程序了!
但是这种方法有很大不足,当我们关闭Xshell后再打开,环境变量又不见了新添加的路径,这是因为我们手动导入的环境变量是内存级变量。
4.修改.bashrc配置文件,让环境变量永久生效
为了避免这样的问题,我们可以在.bashrc里面修改默认的环境变量。先进入用户家目录cd ~,然后打开.bashrc,添加新路径,
然后我们重新打开Xshell,环境变量已更新:
不过,这种方法只适用非常重要的库,我们这样搞就类似为了吃顿醋包了顿饺子。
5. 在/etc/ld.so.conf.d下新增动态库搜索的配置文件,ldconfig生效
先删除刚才添加的环境变量,然后source ~/.bashrc使环境变量立马生效。
其实,还有另外一种方法,在我们的系统中存在一个路径/etc/ld.so.conf.d,
在这个目录中,存在很多系统级别的配置文件,拥有者和所属组都是root,所以我们先切换成root,然后找到/etc/ld.so.conf.d,建立文件ghs.conf,打开ghs.conf这个文件,在里面添加动态库所在的路径:
保存退出即可。然后再让配置文件生效ldconfig(在root下)。
动态库VS静态库
我们编译形成的可执行程序默认链接的是动态库,那静态库什么时候用呢?(动态库和静态库同时提供的时候)我们就需要使用-static选项。如果没有使用-static,并且只提供.a,只能静态链接当前的.a库,其他库正常链接。
我们发现链接动态库和静态库后形成的可执行文件的大小差别很大。
-static的意义是什么呢?必须强制的将我们的程序进行静态链接,这就要求我们链接的任何库都必须提供对应的静态库版本!
使用外部库
学习了动静态库后,我们可以预测一下,如果我们用别人的库,别人应该给我们提供什么呢??一批头文件+一批库文件(.so .a)。