在我们日常开发中,常常会有一些通用的代码,例如:函数,算法等,定时器等,你可能发觉了,当多个模块或多个项目都用到同一个函数或算法的时侯,每次都要重复写一遍它们的代码,费时吃力不说,还有可能因一时的疏漏,造成某次漏了几行代码,这样一来,又得花一番工夫去debug
为了解决上述问题,就出现了库的技术,库本质上是一种可执行代码的二补码方式,可以被操作系统载入显存执行,可以把一些通用的插口放在库中,应用程序假如要使用其中的插口,只须要编译的时侯包含这个库即可
静态库和动态库比较
linux下有两种库,静态库和动态库,它们分别以.a和.so为后缀名,链接时指定静态库文件,编译器会将静态库的目标代码嵌入到可执行文件中,所以可执行文件的容积较大,共享库的代码是在程序运行时才载入显存的,并且可以实现多个程序共享,在编译过程中仅简单的引用,因而代码容积较小
另外,静态库是将目标代码嵌入到可执行程序,所以,后续库的升级须要重新编译可执行程序,而动态库则只须要更新库文件即可,不须要重新编译可执行程序,它的升级相对便捷
下边分别介绍静态库和动态库的生成步骤和使用的技巧
静态库
当前目录是sotest,b.h和b.cpp坐落sotest/lib目录下
// sotest/lib/b.h
#include
#include
#include
using namespace std;
const std::string &UserName();
const std::string &UserPwd();
// sotest/lib/b.cpp
#include "b.h"
std::string g_username = "mytest";
std::string g_userpwd = "654321";
const std::string &UserName()
{
return g_username;
}
const std::string &UserPwd()
{
return g_userpwd;
}关于ar命令见下方的说明
命令格式:arrcslibxxx.afile1.ofile2.o表示生成一个名为libxxx.a的静态库文件
r-插入目标文件到库中
c-创建库文件
s-创建库文件的索引
// sotest/btest.cpp
#include "lib/b.h"
int main(int argc, const char *argv[])
{
cout << UserName() << ", "<< UserPwd() << endl;
return 0;
}使用下边的命令编译代码,编译成功然后执行./mytest,结果如下
动态库
还是以前面sotest/lib目录下的b.h和b.cpp以及sotest/btest.cpp为例来说明动态库的生成和使用方式
步入sotest/lib目录,执行下边的编译命令,编译完成以后,sotest/lib目录下会生成一个libb.so的动态库文件
编译说明:-fPIC告诉编译器形成与位置无关代码,也就是说,形成的代码中,没有绝对地址,全部使用相对地址,所以代码可以被加载到显存的任意位置上,都可以正确的执行。这一点十分重要,也是动态库要求的
还是使用前面的测试代码,步入sotest目录,使用下边的命令编译,并运行,结果如下
命令说明:-L表示指定动态库的路径,假如没有指定表示使用系统默认的搜索路径(通常是/lib或/usr/lib),-lb表示引用libb.so库,引用的时侯省略了上面的lib以及.so后缀
我们发觉编译成功以后,直接运行可执行程序会报错:加载共享库出错,没有这个文件或则目录,这是因为动态链接器加载时找不到动态库
可能有同学会说,里面编译时,不是用-L指定了动态库的路径吗,为何运行的时侯还是提示找不到动态库呢?
这是当然是编译链接和运行加载的区别,里面编译时用-L指定的路径,仅指定了编译链接阶段的库文件搜索路径,它未能决定运行时加载库文件的搜索路径,要确保编译通过linux 查看静态库版本,只要在-L指定的路径中找到了库文件就可以了,但运行与具体的运行环境有关,在编译时难以确定运行时库的搜索路径
所以,运行时提示libb.so未找到,通常有下边几个诱因
1、libb.so库文件本身不存在,须要确保已生成该库文件
2、库文件存在,但不在默认搜索路径中,须要将库文件的路径添加到环境变量LD_LIBRARY_PATH中linux 查看静态库版本linux 论坛,或则将库拷贝到标准路径/lib或/usr/lib下
3、库文件依赖其他库文件,须要确保递归地将所有依赖的库路径添加正确
4、库文件存在且路径正确,但文件名不匹配,比如库文件名是libb.so.1,而程序在找libb.so
5、权限问题,致使未能读取库文件
6、库文件版本不兼容造成读取失败
逐字对比下才会发觉,我们这儿是因为没有设置动态库的路径,设置路径有下边几种方式
1、把libb.so拷贝到/lib或则/usr/lib
执行cp命令把动态库拷贝到/lib目录下,具体操作如右图所示
可以看出,把libb.so拷贝到/lib目录以后,再编译运行,输出就正常了
注意:动态库拷贝到/lib或/usr/lib目录之后,须要再执行sudoldconfig命令刷新/etc/ld.so.cache缓存
2、路径添加到环境变量LD_LIBRARY_PATH
执行export命令把动态库路径/home/smb/wl/mytst/sotest/lib/加入到环境变量LD_LIBRARY_PATH中,之后再运行中标linux,从右图可以看见,最后输出正确
注意:使用export把库路径导出环境变量LD_LIBRARY_PATH的方式,只针对当前SSH联接有效,新打开一个SSH联接的时侯,又须要重新设置,比较好的方法是把环境变量LD_LIBRARY_PATH加入到~/.bashrc中,这样就对当前用户有效,假如把它加到/etc/bashrc中,就对所有用户有效
3、路径添加到/etc/ld.so.conf中
如右图,打开/etc/ld.so.config,写入动态库路径
执行sudoldconfig命令刷新/etc/ld.so.cache缓存,之后运行可执行程序,结果如右图
在里面打开/etc/ld.so.config的时侯,我们发觉第一行是:includeld.so.config.d/*.conf,它表示我们也可以把动态库路径放在一个自定义的配置文件中,之后把这个配置文件拷贝到/etc/ld.so.conf.d/目录中即可,可执行程序加载动态库的时侯,会手动去自定义配置中目录中搜索,把库目录写入到自定义配置my.conf中
把自定义配置my.conf拷贝到/etc/ld.so.conf.d/目录中,并使用ldconfig命令刷新缓存
最后,运行可执行程序,可以看出,复印正确
怎么查看程序链接的动态库
使用lddbtest_so命令可以查看可执行程序加载了什么动态库以及每位动态库的路径
如上图所示,红框的部份是自己编撰的动态库以及动态库的路径,假如加载动态库失败,则会显示"notfound"的字样,如右图
小结
本文主要介绍了linux下动态库和静态的生成和使用方式,尽管都是比较基础的知识,但还是要亲自动手练习能够熟练把握
近来好多男子伴找我要一些程序员必备资料,于是我翻出了压箱底的宝藏,免费分享给你们!
扫描海报二维码免费获取。