【问题标题】:Best way to expose custom location of shared library in Linux在 Linux 中公开共享库的自定义位置的最佳方法
【发布时间】:2014-03-17 16:37:44
【问题描述】:

我目前正在寻找在 Linux 上公开共享库位置的方法,以便任何单独安装的程序都可以轻松获取它。我想让这个位置可配置,以便它可以指向同一个库的不同可能安装。我能想到的类似案例有 Qt5 和 Java。

长话短说,我正在开发FreeRDS,这是一个基于FreeRDP 的远程桌面服务堆栈。服务器端 RDS 感知应用程序链接到 libwinpr-wtsapi,这是一个公开 Microsoft Windows 终端服务 API 接口但不实现它的存根库。这使应用程序能够链接到 libwinpr-wtsapi,而无需直接链接到特定的 RDS 实现。在第一次调用任何 WTSAPI 函数时,真正的实现由 libwinpr-wtsapi 动态加载。但是,需要知道实现 WTSAPI(此处为 FreeRDS)的动态库的位置。

现在,我通过设置具有库的完整路径的环境变量来实现这一点:

export WTSAPI_LIBRARY=/opt/freerds/lib/x86_64-linux-gnu/libfreerds-fdsapi.so

但是,这不是很实用,因为需要使用WTSAPI 为每个程序设置此环境变量。在这种情况下,我在 /opt/freerds 中安装了 FreeRDS。

我想我可以通过使用单个环境变量在系统上公开FreeRDS 的安装前缀来简化这一点,类似于 JAVA_HOME:

export FREERDS_HOME=/opt/freerds

但是,我需要知道正确的库子目录。同样重要的是要知道,将来有可能同时提供32-bit64-bit 版本的库,提供FreeRDS WTSAPI。这个库基本上使用FreeRDS 会话管理器执行RPC,所以这绝对是可能的。

假设我们正确设置了FREERDS_HOME,或者FreeRDS 安装在系统的默认安装前缀中,哪些文件将是“标准”以提供一些额外的安装配置信息?在这里,我想我可以有一个等效于Qt5qt.conf,它将特定的安装子目录,如64-bit 安装子目录、32-bit 安装子目录等。但是,我不知道在哪里我应该把那个文件。应该在<prefix>/etc/freerds/freerds.conf吗?

想法,有人吗?谢谢!

【问题讨论】:

  • 为你喜欢的发行版打包它;将其安装在/usr/lib/libfreerds-fdsapi.so 或附近。
  • "... 使此位置可配置,以便它可以指向同一库的不同可能安装。": "different" in条款是什么?发布版本、平台、功能?
  • 系统范围的库路径在 /etc/ld.so.conf 中配置,是你需要的吗?
  • 您始终可以通过dlopen()dlsym() 设置函数指针,而不是直接将库链接到您的目标。这将需要您进行一些额外的编码,但是以干净、易于阅读的方式支持库的多个版本变得非常容易。
  • WTSAPI 实现 (libfreerds-fdsapi.so) 已经是一个旨在由 libwinpr-wtsapi.so 动态加载的库。 libfreerds-fdsapi.so 导出单个入口点,该入口点返回指向回调数组的指针。 libwinpr-wtsapi.so 导出具有相同签名的函数,并调用动态加载的回调。这允许程序链接到 libwinpr-wtsapi.so,而无需直接链接到特定的 WTSAPI 实现。

标签: c linux shared-libraries


【解决方案1】:

今天的一些(很多?全部?)Linux 发行版包括environment-modules,其目的正是通过使用简单的前端自定义环境(最终,shell 别名/功能)来提供同一软件的许多不同版本命令。

您可以找到所有需要的信息here

【讨论】:

  • 我不了解环境模块,但我认为这不适合我的情况。如果我错了,请纠正我,但是查看“快速示例”似乎需要手动切换模块才能使更改生效。假设我在 /usr 中有一个普通的 FreeRDS 安装,在 /opt/vendor 中有一个特定于供应商的安装。我想在系统上全局公开 /usr 或 /opt/vendor 作为我的 FREERDS_HOME,并能够配置该路径。像 /etc/freerds/freerds.conf 这样的全局路径中的配置文件可以做到这一点,但我不确定它是否是“标准的”。
  • 使用模块,您只需让用户能够 1. 立即查看可用的版本 (module list) 和 2. 从其中选择一个(module loadmodule switch )。只需设置 FREERDS_HOME 即可。对于“标准”位置,我认为/etc/freerds 是系统范围安装的位置,即 /usr 下的位置。我希望在 /opt/vendor/etc 中找到 /opt/vendor 中的配置文件。我不确定他们应该引用相同的配置文件:如果不同的版本支持不同的配置选项怎么办?
【解决方案2】:

感谢您的多个回答,这是我最终选择的满足我需求的解决方案:

如前所述,同一系统上可能安装了多个 FreeRDS,但一次只能运行一个。我们还可以假设 FreeRDS 应该在我们尝试与之交互之前运行。知道了这一点,我修改了 FreeRDS,在 /var/run/freerds.instance 中编写了一个简单的配置文件,其中包含安装前缀和安装子目录。这与拥有一个 .pid 文件非常相似,只是我们要公开安装路径。

freerds.instance 文件使用 .ini 格式,这在配置文件中很常见。 libwinpr-wtsapi 所要做的就是解析 /var/run/freerds.instance 以找到当前 FreeRDS 实例的安装前缀以及库子目录,这样我们就可以找到正确的 libfreerds-fdsapi.so。

这是一个示例 freerds.instance 文件的样子:

[FreeRDS]
prefix="/opt/freerds"
bindir="bin"
sbindir="sbin"
libdir="lib/x86_64-linux-gnu"
datarootdir="share"
localstatedir="var"
sysconfdir="etc"

我更喜欢这个解决方案,因为它实际上不需要特殊配置、环境变量设置等。无论如何,我们总能在系统上的任何位置找到正确的 FreeRDS 安装。

【讨论】:

    【解决方案3】:

    您可以将$ORIGIN rpath 添加到您的可执行文件,使其加载相对于可执行文件所在目录的库。(请参阅“ld: Using -rpath,$ORIGIN inside a shared library (recursive)”)。这可能也适用于dlopen()。?

    $ gcc ... -Wl,-rpath,'$ORIGIN/../lib/dir' -lsomething 
    

    我还发现您可以直接运行动态链接器来获得一些调试工具:

    $ /lib/ld-linux.so.2
    Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]
    ...
       --list                list all dependencies and how they are resolved
    

    【讨论】:

    • 我已经在为我的二进制文件使用相对 RPATH。我们在这里讨论的是动态加载一个我们以前不知道位置的库,这是另一回事。
    【解决方案4】:

    导出 LD_LIBRARY_PATH=/yourso.so

    【讨论】:

      猜你喜欢
      • 2012-06-13
      • 2022-10-18
      • 1970-01-01
      • 1970-01-01
      • 2011-02-28
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多