Linux共享库概述( 七 )

  • void *handle;
  • char *error;
  • double (*cosine )(double);
  • handle = dlopen("/lib/libm.so.6", RTLD_LAZY);
  • if(!handle){
  • fputs(dlerror(), stderr);
  • exit(1);
  • }
  • cosine = dlsym(handle, "cos");
  • if((error = dlerror()) != NULL){
  • fputs(error, stderr);
  • exit(1);
  • }
  • printf("%f", (*cosine)(2, 0));
  • dlclose(handle);
  • return 0;
  • }
  • 如果这个程序名字叫foo.c,那么用下面的命令来编译:
    gcc -o foo foo.c –ldl
    共享库共享库是程序启动时加载的库 。 共享库安装正确后 , 所有启动的程序将自动使用新的共享库 。 它实际上比这更灵活和复杂 , 因为Linux使用的方法允许您:
    • 更新库并且仍然支持希望使用这些库的旧版 , 非后向兼容版本的程序;
    • 在执行特定程序时 , 重写特定库或甚至库中的特定函数 。
    • 在程序使用现有库运行时执行所有这些操作 。
    约定对于共享库来支持所有这些所需的属性 , 必须遵循许多约定和准则 。 您需要了解图书馆名称之间的区别 , 特别是“soname”和“实名”(以及它们的相互作用) 。 您还需要了解它们应该放在文件系统中的位置 。
    共享库名称每个共享库都有一个名为“soname”的特殊名称 。 soname具有前缀``lib'' , 库的名称 , 短语“.so” , 后跟一个句点和一个版本号 , 每当界面改变时都会递增(作为一个特殊的例外 , 级别C库不以“lib”开头) 。 一个完全合格的soname包含作为前缀的目录; 在一个工作系统上 , 一个完全合格的soname只是一个与共享库的“真实姓名”的符号链接 。
    每个共享库还有一个“实名” , 它是包含实际库代码的文件名 。 真正的名字增加了一个时期 , 次要号码 , 另一个时期和发行号码 。 最后一个期间和发行号码是可选的 。 次要号码和发行号码通过让您准确知道安装了哪些版本的库 , 来支持配置控制 。 请注意 , 这些数字可能与用于在文档中描述库的数字不同 , 尽管这样做更容易 。
    另外 , 编译器在请求库时使用的名称(我将其称为“链接器名称”) , 这只是没有任何版本号的soname 。
    管理共享库的关键是这些名称的分离 。 程序在内部列出他们需要的共享库时 , 应该只列出他们需要的soname 。 相反 , 创建共享库时 , 只能创建具有特定文件名的库(具有更详细的版本信息) 。 当您安装新版本的库时 , 将其安装在几个特殊目录之一中 , 然后运行程序ldconfig(8) 。 ldconfig检查现有文件 , 并将声名创建为真实名称的符号链接 , 以及设置缓存文件/etc/ld.so.cache(稍后描述) 。
    ldconfig不设置链接器名称; 通常这是在库安装期间完成的 , 链接器名称简单地创建为“最新”的soname或最新的真实名称的符号链接 。 我建议将链接器名称作为与soname的符号链接 , 因为在大多数情况下 , 如果您更新库 , 那么您希望在链接时自动使用它 。 我问HJ Lu为什么ldconfig不会自动设置链接器名称 。 他的解释基本上是你可能想使用最新版本的库来运行代码 , 但是可能需要 开发 链接到旧的(可能不兼容的)库 。 因此 , ldconfig不会对您希望程序链接的任何假设 , 因此安装程序必须特别修改符号链接以更新链接器将用于库 。
    因此 , / usr /lib/libreadline.so.3是一个完全限定的soname , 其中ldconfig将被设置为与/usr/lib/libreadline.so.3.0之类的一些真实名称的符号链接。 还应该有一个链接器名称 /usr/lib/libreadline.so, 它可以是引用/usr/lib/libreadline.so.3的符号链接。
    3.1.2 。 文件系统放置共享库必须位于文件系统的某个位置 。 大多数开源软件往往遵循GNU标准; 有关更多信息 , 请参阅info:standards#Directory_Variables上的信息文件文档。 GNU标准建议默认安装/ usr / local / lib中的所有库 , 当分发源代码(所有命令都应该进入/ usr / local / bin)时 。 它们还定义了覆盖这些默认值和调用安装例程的约定 。