1. 动态库文件的扩展名是“.so”,而静态库文件的扩展名是“.a”按照约定,所有动态库的文件名的形式是libname.so (可能在名字中加入版本号)。这样, 线程函数库便被称作libthread.so。静态库的文件名形式是libname.a,共享archive的文件名 形式是libname.sa。共享archive只是一种过渡形式,帮助人们从静态库转变到动态库。共享 archive现在也已过时。
2. 例如,你通过-lthread选项,告诉编译链接到libthread.so传给C编译器的命令行参数里并没有提到函数库的完整路径名。它甚至没有提到在函数 库目录中该文件的完整名字!实际上,编译器被告知根据选项-Iname链接到相应的函数库, 函数库的名字是linbname.so——换句话说,“lib”部分和文件的扩展名被省掉了,但在前面 加一个 “1” 。
3. 编译器期望在确定的目录找到库
这里,你可能会疑惑,编译器是怎么知道该往什么目录寻找函数库呢?就像存在一种特 殊的规则用于查找头文件一样,编译器也自有办法来寻找函数库。它查看一些特殊的位置, 如在/usr/lib中查找函数库。例如,线程库位于/usr/lib/libthread.so。
编译器选项-Lpathname告诉链接器一些其他的目录,如果命令中加入了-1选项,链接 器就往这些目录查找函数库。系统中存在几个环境变量,LD_LIBRARY_PATH和 LD—RUN一P:ATH,也是用于提供这类信息。出于安全性、性能和创建/运行独立性方面的考虑, 使用环境变量的做法现在己经不提倡。一般还是在链接时使用-Lpathname和-Rpathname选项。
4. 观察头文件,确认所使用的函数库
你有可能遇见的另一个关键问题是“我怎么知道必须链接到哪些函数库? ”答案正如 ObiWanKenobi在伽所清楚表达的那样(大意):“卢克,使用源码! ”。如果观察程序 中的源代码,就会发现自己调用了一些自己不曾实现的函数。例如,如果程序跟三角有关, 可能会调用像sin()和cos〇这样的函数,它们可以在math函数库中找到。文档中显示了每个 函数期望接收的正确的参數类型,并说明它位于哪个函数库。
一个很好的建议就是可以观察程序所使用的相#include指令。在程序中所包含的每个头文 件都可能代表一个必须链接的库。这个建议也适用于C++。这里出现了-…个名字不一致的大 问题。头文件的名字通常并不与它所对应的函数库名相似。非常遗憾丨这是你“不得不知道 的” C语言的一个混乱之处。表5-1展示了一些常见的例子。
函数库链接所存在的另一个不一致性就是函数库所包含的某个函数的原型可能与其他头 文件中所声明的函数的原型一样。例如,在头文件<string.h>、<stdio.h>和<time.h>中声明的 函数通常是在同一个库libc.so中提供。如果你不信,可以使用run工具程序列出函数库所包 含的函数。