【问题标题】:Load shared library by path at runtime在运行时按路径加载共享库
【发布时间】:2011-11-29 09:41:30
【问题描述】:

我正在构建一个 Java 应用程序,该应用程序使用一个用 C++ 编写并针对不同操作系统编译的共享库。问题是,这个共享库本身依赖于它通常在适当的环境变量(PATHLIBRARY_PATHLD_LIBRARY_PATH)下找到的附加库。

我可以——但不想——设置这些环境变量。我宁愿在运行时从给定路径加载所需的共享库 - 就像插件一样。不 - 我不希望任何启动应用程序在新环境中启动新进程。有人知道如何实现吗?

我知道这一定是可能的,因为我使用的其中一个库能够从给定路径加载其插件。当然我更喜欢平台无关的代码,但如果这不可能,Windows、Linux 和 MacOS 的单独解决方案也可以。

编辑 我应该提到我希望使用的共享库是面向对象的,这意味着单个函数的绑定不会这样做。

【问题讨论】:

标签: c++ plugins shared-libraries


【解决方案1】:

在 Windows 上,您可以使用 LoadLibrary,在 Linux 上,dlopen。 API 非常相似,可以通过提供完整路径直接加载 so/dll。如果它是运行时依赖项(加载后,您通过调用 GetProcAddress/dlsym 来“链接”。)

【讨论】:

    【解决方案2】:

    在 UNIX/Linux 系统中,您可以使用 dlopen。那么问题是你必须通过dlsym获取你需要的所有符号

    简单示例:

    typedef int (*some_func)(char *param);
    
    void *myso = dlopen("/path/to/my.so", RTLD_NOW);
    some_func *func = dlsym(myso, "function_name_to_fetch");
    func("foo");
    dlclose(myso);
    

    将加载 .so 并从那里执行 function_name_to_fetch()。有关更多信息,请参见手册页 dlopen(1)。

    【讨论】:

    • 我想我应该补充一点,共享库本身是面向对象的。如果只有函数可以“链接”,那就不行了,对吧?
    • 如果您知道链接器生成的名称,您可以访问任何符号。一个好的做法是使用 C 调用约定的函数,该函数返回指向包含对象或其他内容的结构的指针。
    • 好吧,我已经这样做了 - 通过 Java 访问库。我正在编写的 C++ 库不过是使用第三方库(我无法更改)的存根。
    【解决方案3】:

    我认为你做不到。

    大多数 Dll 都有某种 init() 函数,必须在加载后调用,有时该 init() 函数需要一些参数并返回一些句柄以用于调用 dll 的函数。你知道附加库的定义吗?

    然后,第一个库不能仅通过其名称来简单地查看 DLL X 是否在 RAM 中。它需要的那个可以在不同的目录或不同的构建/版本中。如果完整路径与已加载的另一个路径相同,操作系统将识别该库,并且它将共享它而不是再次加载它。

    另一个库可以从另一个路径加载它的插件,因为它不依赖于 PATH 并且它们是他自己的插件。

    您是否尝试在加载 Dll 之前从代码中更新进程的环境变量?这不取决于启动程序。

    【讨论】:

    • 这不是真的——许多大型第 3 方库使用动态库加载来实现插件系统。必须将函数标记为 extern "C" 块到 ensure c-linkage 并防止名称混淆。确实,Windows API 为 DLL 的加载指定了一个入口点(除其他外)。但是,这取决于平台。
    【解决方案4】:

    我同意其他关于使用 dlopen 和 LoadLibrary 的海报。 libltdl 为您提供了与这些功能无关的平台接口。

    【讨论】:

      猜你喜欢
      • 2012-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多