Linux Program Library Howto 摘记

本篇来自阅读 Program Library Howto 文档后的笔记。此文有德文、日文、希腊文翻译,可惜没中文翻译。如果谁有兴趣翻译之,欢迎联系我,我或许也可以帮上忙。(更新:本文档的原始出处在此,发现原来读了半天,读的不是最新版!很汗!囧)这篇文档我并没有读完,阅读时,所关心的重点是,大致的概念,以及如何生成和使用静态库、共享库。

笔记比较凌乱,如果您有兴趣,将就着「去了糟粕」地阅读吧。

1、在 C++ 中调用 C 共享库例程的 name-mangling 问题,基本解决方式,即在 C 共享库的源文件里,做如下处理。

#ifdef __cplusplus
extern "C" {
#endif
// code here.
#ifdef __cplusplus
}
#endif

2、静态库的生成和使用,即另一篇 AutoTools 指南的 4.3 节所讲述的 ar(1)ranlib(1) 方式,不过其实 ar rcs 就已经增添了 index 信息,无须再次调用 ranlib(1) 生成或更新 index 信息。如下。

gcc -g -Wall -c -o libfoo-static.o libfoo.c
ar rcs libfoo-static.a libfoo-static.o

3、共享库的生成和使用。(共享库相对于静态库的好处就不多言了。)

3.1、对于共享库(Shared Library)的名称和放置目录,有几个约定,如下。

名称
以一个称作 foo 的库为例。真实名称,如 libfoo.so.2.6.1 ,共享库名称(被称作 soname),如 libfoo.so.2 ,链接名称,如 libfoo.so 。真实名称是文件本身。「共享库名称」和「链接名称」都是软链接,前者指向「真实名称」,后者指向前者。

目录
自己写的共享库,或者网上下载的、试验性质的库,放置在 /usr/local/lib 即可。在可以通过 gcc 的 -L 选项指定具体位置,这在库开发中貌似更实用。

3.2、共享库如何被使用

这里暂时不涉及 gcc 命令,从概念上做阐述。

/etc/ld.so.conf 文件中包含了共享库的搜索目录,在我当前的机器上,是包含了 /etc/ld.so.conf.d 目录下所有 conf 文件,这么做,可以将各个不同类型的共享库索引,放置在不同的配置文件中(如 C 开发的、显卡开发相关的等等)。

/etc/ld.so.preload 文件里的共享库,相对于前者,有更高的加载优先级,如果标准 conf 加载 libfoo.so.3.2 版本,而你想加载 libfoo.so.2 里的接口,那么可以利用 preload 做处理(没试过,具体还有待尝试)。

/etc/ld.so.cache 缓存了很多常见的共享库(如 libc 库),通过 ldconfig -p 命令,查看当前已被缓存的库。
这方面的信息,还可以参见 ldconfig(1) 中的 FILES 部分。

使用 ldd 命令,来查看某个程序,或者共享库,对其他库的依赖关系。3.5 节的末尾讲述了使用 ldd 的危险性,不要将其应用于不信任的程序上。

3.3、环境变量的设置

这一节貌似主要涉及到调试,例如 LD_LIBRARY_PATH LD_DEBUG LD_PRELOAD 等等,譬如可以尝试 export LD_DEBUG=libs,files 再运行某个程序,通过 export LD_DEBUG=help 查看帮助信息。本节还提到了系统对于 setuid/setgid 程序,会限制共享库的链接,暂时先了解,不深入了。

3.4、如何生成一个共享库

实战部分了。这里给出命令概述,具体信息参考 gcc(1)ld(1) 的手册。

gcc -fPIC -g -c -Wall a.c
gcc -fPIC -g -c -Wall b.c
gcc -shared -Wl,-soname,libmystuff.so.1 \
-o libmystuff.so.1.0.1 a.o b.o -lc

本节进一步说明了 -fpic-fPIC 的区别,以及有时候(以上述的案例为例),当共享库 libmystuff.so 需要某些 a.o 或者 b.o 中符号表信息(此类情况被称作「reverse dependencies」逆向依赖)时,编译两个源文件时需要增加 -WI,-export-dynamic 选项,即 gcc -fPIC -g -c -Wall -Wl,-export-dynamic a.c ,将所有符号放置在动态符号表(Dynamic Symbol Table - 并不太清楚其含义,有时间可详细了解 ELF 文件内在结构)中。

最后,提到了 runtime library path 概念,即 -Wl,-rpath,/PATH_HERE 选项。这个同 gcc 的 -L 选项、或是环境变量的 LD_LIBRARY_PATH 是异曲同工。

3.5、如何安装一个共享库

这里讲的很详细,但是一般应该没这么麻烦 囧,按照我的理解,如下处理可能最简单。

将自己写的共享库,放到 /usr/local/lib/mylib/libfoo.so.1.0.1 然后修改 /etc/ld.so.conf.d/mylib.conf 文件,将 /usr/local/lib/mylib 添加进去,接着运行 ldconfig --verbose 即可。

ldconfig 会负责建立各个软链接,并更新 /etc/ld.so.cache 缓存。但是要注意,考虑到兼容性ldconfig 并不会生成最终的「链接名称」即类似 libfoo.so 的软链接,而止步于「共享库名称 soname」。这需要用户自己决定,是否生成 soname 链接,具体原因参考 3.1.1 节末尾段落(其实也就是基于后向兼容性的考虑)。

同静态库的使用一样,使用 -lfoo 来使用 libfoo.so 共享库(还可通过 -L 来指定库的搜索路径,但是做了上述 /etc 文件处理后,-L 就可有可无了)。

3.6、向后兼容的库

讲述什么是向后兼容(Backward Compatible)的库,以及如何做处理。很好的章节。非常值得一读。
遵循若干原则,就可以保证 C 语言编写的共享库,拥有一个向后兼容的 ABI 即 Application Binary Interface 。本节还有一个 C++ 的建议表单,由于 C++ 语言的某些内部处理,譬如 name-mangling 操作,这些建议明显比 C 语言要「繁杂」很多。 =_=

这个章节给出了一个小型案例

另外,本指南还涉及如何动态加载(Dynamically Loaded)库,以及诸多进阶或附带主题,暂时不关注。备忘在此吧。

- EOF -

原文地址:https://www.cnblogs.com/jtuki/p/linux_program_library_howto_note.html