java如何构建从另一个DLL调用函数的JNI DLL?杰尼,格雷德尔
我已经在这个repo中实现了IDEA网站的JNI指南中给出的示例(你可以在那里看到fork),现在它甚至可以在我的AARC64 Mac上运行现代JDK和JUnit测试(希望它可以在其他任何地方运行)。但我真的不明白Gradle子项目文件夹中的build.gradle
发生了什么。我可以识别那里的编译器参数,但include选项是在不同的方法中设置的,这让我感到困惑
我的目标是让包装器C-file执行dlopen
(或其Windows的替代方案),并从动态库运行一些函数
例如
<ProjectRoot>/hello/src/main/c/ wrapper-with-JNI-call-convensions.c
libsomelib.dylib
libsomelib.so
somelib.dll
Calls looks like this: Java -[JNI]-> wrapper.dll -> somelib.dll
^ ^ ^
| | |
building wrapper.c using Gradle to this
因此,如果我只使用两个C源文件(使用JNI和我库的C源代码的包装器)运行build,我已经成功地使JNI工作(同时不改变样本中的build.gradle
)。然后,我使用macOS内置的clang
编译器构建了dylib
,并编写了正确的dlopen
和dlsym
代码。但当我构建项目时,dlopen
调用返回空值
我曾尝试向build.gradle
添加一些参数,该参数用于编译使用动态库的二进制文件,但没有帮助
我的测试运行在这里退出:
// my wrapper
void* dlHandle = dlopen("libsomelib.dylib", RTLD_LAZY);
if (dlHandle == NULL) {
printf("DLL NOT OPENED !!!\n");
exit(0);
}
我知道我必须在包装器中编写适当的依赖于平台的调用,这对我来说没什么大不了的
那么你能告诉我如何使用Gradle让它正常工作吗?记住,在我的例子中,目标是只有JNI就绪*.c
包装器和动态链接库*.so & *.dylib & *.dll
更新:我决定不使用Gradle,我使用VSCode tasks.json
,它的直观性要高出20倍。我会写下我的方法作为自我回答
# 1 楼答案
要使其运行,您可以尝试以下操作:
我假设当前目录中有
libsome.dylib
。然后可以在JNI
内加载libwrapper.dylib
,它引用另一个库:libsome.dylib
更新
假设你有两个文件:
和相应的头文件
你可以用它建立一个库,方法如下:
这将相当于您的:
somelib
然后,我们可以有这样的东西:
我们声明函数并使用它。名称将在链接阶段稍后解析
现在,您可以编译
wrapper
库了。在这个示例中,它是HelloWorld
现在,在
JNI
内,您所做的就是:由于
HelloWorld
与共享库another
链接,它将可以访问其符号。所以,您不需要使用dlopen
试试这个示例(甚至还有基于Docker的文件,所以您不必费劲地设置环境)
# 2 楼答案
作为@Oo。oO提到的this菜谱正是我需要的。这是一种动态加载方法,适用于Mac和Linux。此外,正如他所提到的,静态链接方法在他的回答中得到了演示
我还想在其中添加一些编译器选项:
在lib的源代码中,还应该定义
然后在每个函数声明之前的头文件中,或者在每个定义之前的源文件中,为您希望从外部或库中使用的函数编写它
例如
或者
这个答案将在以后的Windows案例中给出
摘要
macOS+
clang
&;Linux+gcc
Dynamic load of DLL
Static linking DLLs