2011-10-02 54 views
15

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

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

我知道这一定是可能的,因为我使用的一个库能够从给定的路径加载它的插件。当然,我更喜欢独立于平台的代码,但如果这是不可能的话,Windows,Linux和MacOS的独立解决方案也会这样做。

编辑 我应该提到的是,共享库我想用的是面向对象的,这意味着单一功能的结合不会去做。

+0

如何从Java加载库? –

+0

Java Native Access(JNA) – aRestless

回答

8

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

15

可以使用的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)。

+0

我想我应该补充说共享库本身是面向对象的。如果只有函数可以“链接”,这是行不通的,对吧? – aRestless

+0

如果您知道链接器生成的名称,则可以访问任何符号。一个好的做法是有一个使用C调用约定的函数,它返回一个指向包含对象或某物的结构的指针。 – johannes

+0

那么,我已经这么做了 - 通过Java访问库。我正在写的C++库不过是一个使用第三方库(我无法改变)的存根。 – aRestless

1

我不认为你可以这样做。

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

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

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

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

3

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