找到一个linux静态库动态库的好资料.3
# 正文继续整理从这个页面学到的东西:https://tldp.org/HOWTO/Program-Library-HOWTO。
之前的在这里:
找到一个linux静态库动态库的好资料.0
找到一个linux静态库动态库的好资料.1
找到一个linux静态库动态库的好资料.2
这一篇继续看这个: https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
这个页面主要讲共享库,原文是shared libraries。就是linux里常见的后缀为.so的文件,此中so是缩写了“shared object”。共享库是在程序启动时就加载。只要共享库是被正确得安装了,那么后续启动的所有程序都会自动使用新的共享库。共享库的设计非常精良,这些设计精良到支持你这么整:
- 如果新的共享库与之前的不兼容,就可以让一些程序仍旧使用旧库的条件下,让新程序使用新的库。
- 在执行某个程序时使用指定的、“重写”过的库或“重写”过的函数。
- 在程序正在使用着已有共享库的过程中做上边2件事情。
要做到上边说的事情,得遵守若干关于共享库的惯用方式。要搞清晰这些共享库的惯用方式,起首要搞清晰共享库的各种名字,比如so名、真实名。还得搞清晰共享库该保存在哪里。这的“so名”和“真实名”是直接翻译自原文的“soname”和“real name”,我以为这里使用原词更方便一些,所以下文就是用“soname”和“real name”了。先上个图:
https://i-blog.csdnimg.cn/direct/23e2a5dd0e4c44b0ad7512f6f5bbc588.png
上图赤色圆圈里的,就是soname,就说libselinux.so.1吧,“lib”是个前缀,“.so”是扩展名,“.1”是个版本号。一般最底层的C库名字并不以“lib”作为前缀,好比上图的linux-vdso.so.1。原文还有一个概念叫“fully-qualified soname”,就是带路径的soname。一个“fully-qualified soname”通常是个软毗连,比如下图的/lib64/libpcap.so.2:
https://i-blog.csdnimg.cn/direct/aae4510ac34140a8b7a822ac1f845061.png
上边图上的/lib64/libcap.so.2.48就是real name了,此中的“.2”的2是次版本号,“.48”的48是release号;release号是可选的,不一定得有。“.2.48”这种次版本号+release号的约定,是为了让人看到即知晓具体的库版本。
还有一个名字,就是编译器调用共享库时使用的名字,即以“.so”结束的,比如/lib64/libcap.so。原文作者管这个叫“linker name”,咱也跟着叫吧。
原文作者认为要盘共享库,关键就是搞清晰这些个名字。还说:
列出程序需要的共享库时,只列出so名即可(上上个图,带圆圈的那个);
然后说,当创建一个共享库时,只是创建了一个带有版本信息的文件;
当需要安装一个新版本的共享库时,就要把它放到指定的目录,再执行ldconfig(8)。
ldconfig会检查目录里有哪些文件,创建指向文件的符号链接、同时设置缓存文件/etc/ld.so.cache
ldconfig不会去管linker name(链接器使用的名字)的事情。
通常,linker name是在安装共享库时手动设置:即创建一个指向最新版本的共享库的软毗连。
原文作者说他问过H.J. Lu这个问题:为何ldconfig不设计为自动设置linker name?得到的回答基本是这个意思:用户也有大概想让开发环境使用旧的库,所以ldconfig不做任何假定,而是让用户必须单独举行一下更新软毗连的操纵。
总结一下:/usr/lib/libreadline.so.3是个“fully-qualified soname”,它通常是个由ldconfig创建的软毗连,指向一个真实名类似 /usr/lib/libreadline.so.3.0的共享库文件;还有一个链接器使用的名字linker name,/usr/lib/libreadline.so,它是指向/usr/lib/libreadline.so.3的软毗连,通常是手动设置的。
到这里应该去试一下的,但是要试一下就得用ldconfig,所以还得再说一下ldconfig。我们要先知道有一个东东叫程序加载器,原词program loader,它是操纵系统的提供的,负责在启动程序时将程序文件和库文件放到内存里,并为程序的执行做一些准备性工作。有的程序需要很多的共享库,那么在启动时查找若干目录并加载它们,这就很低效,所以就引入了缓存机制。
ldconfig(8)就是用来创建这些缓存的,如此,程序启动时程序加载器就直接使用缓存里的共享库,服从就比较高了。
现在我们去看ldconfig(8)的man page。上边说ldconfig会搜索一些目录,创建一些须要的符号毗连,这些符号毗连指向最新的共享库(shared linraries);“一些目录”包含命令行传入的目录、/etc/ld.so.conf里配置的目录、以及/lib、/usr/lib(/lib64、/usr/lib64)。这些缓存由run-time linker(即ld.so或ld-linux.so)使用。
https://i-blog.csdnimg.cn/direct/289a24a0b98448c18f623858ff19310e.png
ldconfig创建的缓存都是保存在/etc/ld.so.cache里。/etc/ld.so.cache是一个二进制文件,保存了动态库的列表;ldconfig -p可以打印这个列表:
https://i-blog.csdnimg.cn/direct/9e6b28203ca641c996ca15a9ebd082af.png
https://i-blog.csdnimg.cn/direct/ae5f7ea2df5840268cddea47de4168a2.png
https://i-blog.csdnimg.cn/direct/b062599b48c3474481dbc86ea71a2a84.png
好了,我们现在编一个动态库,试试上边说的这些。实在《找到一个linux静态库动态库的好资料.1.docx》里面的共享库示例就说到一个,刚才看了下,实在很适合贴到这里来。不过我打算再练习一下,弄得稍微不一样一点儿,所以再试一次,一边试一边记录,写到哪里算哪里。
前边说ldconfig会根据/etc/ld.so.conf配置的目录创建缓存,而/etc/ld.so.conf里面只有一行:include ld.so.conf.d/*.conf:
https://i-blog.csdnimg.cn/direct/07f7281ff4ab474a8f6cf3c7bfb1b65e.png
所以我们在/etc/ld.so.conf.d/目录下新加一个配置文件test.conf,里面配上本次测试用的目录/root/nice-teammate:
https://i-blog.csdnimg.cn/direct/a7a47398dc2842b594e516055377fd57.png
现在我们编一个real name为libhello.so.0.0的共享库,命令贴在这里了:
gcc -fPIC -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0 libhello.c -lc
https://i-blog.csdnimg.cn/direct/65d14ba28dd84a1cbb5cd75ceaef6248.png
然后,我们使用ldconfig将其参加缓存:
https://i-blog.csdnimg.cn/direct/125eaf719a8741dd8ea2b6114ba5490b.png
我们发现ldconfig创建了一个软链接名曰libhello.so.0。
看起来这个libhello.so.0与gcc的选项-Wl,-soname,libhello.so.0有关,所以去掉这个选项再试一把:
https://i-blog.csdnimg.cn/direct/bf647c0ecaf94525bef86803eff198c4.png
可以发现ldconfig列出的soname为libhello.so.0.0,也不创建什么软毗连了(因为也不需要)。
现在我们照旧按指定soname为libhello.so.0的方式:
https://i-blog.csdnimg.cn/direct/0b4af3080bd2476f8bab1b618c550597.png
然后手动创建一个软毗连:ln -sf libhello.so.0 libhello.so
https://i-blog.csdnimg.cn/direct/dd60ea02d8354d5da872c0a480ae204d.png
创建一个main.c代码如下:
https://i-blog.csdnimg.cn/direct/43252b8f8adc451a8d266f28d43923a1.png
然后编译可执行程序main,使用命令:gcc -o main main.c -L ./ -lhello
https://i-blog.csdnimg.cn/direct/42326d87080e4ef183c5c3a6c078f5dc.png
https://i-blog.csdnimg.cn/direct/7ebdbc1a6d9b42be934dcd7ab930c857.png
哦,大概是不手动创建给编译器用的软链接libhello.so,那gcc的-lhello就不方便了。
看起来已经是一片相称凑合的文章了,欧。
# ENDNOTES
e1
https://i-blog.csdnimg.cn/direct/9c30950a93874d1a8741e1f4b8d3682c.png
e2
这里的“重写”即override,类似java语法里子类重写父类方法的意思,原文是:override specific libraries or even specific functions in a library when executing a particular program.
e3
https://i-blog.csdnimg.cn/direct/f762a8173ca34d3ea287eac5688493af.png
e4
在unix系统中,程序加载器除了去调exec系统调用(原文是:The loader is the handler for the system call execve().),任务还包括:
- 校验权限,内存需求等
- 把保存着指令的可执行文件放入内存
- 把命令行的参数放到内存
- 初始化寄存器
- 跳到程序的入口
参考:https://en.wikipedia.org/wiki/Loader_(computing)
看下了《UNIX环境高级编程》的8.3节,基本也是这个意思。
e5
这一个小自然段就是https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html上的,原文是:Searching all of these directories at program start-up would be grossly inefficient, so a caching arrangement is actually used. The program ldconfig(8) by default reads in the file /etc/ld.so.conf, sets up the appropriate symbolic links in the dynamic link directories (so they'll follow the standard conventions), and then writes a cache to /etc/ld.so.cache that's then used by other programs. This greatly speeds up access to libraries. The implication is that ldconfig must be run whenever a DLL is added, when a DLL is removed, or when the set of DLL directories changes; running ldconfig is often one of the steps performed by package managers when installing a library. On start-up, then, the dynamic loader actually uses the file /etc/ld.so.cache and then loads the libraries it needs.
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]