在 Linux 上的 Spring Boot 中使用 JNA 加载 .so 文件时出现问题

dav*_*idl 2 java linux jna spring-boot

我有一个使用 Spring Boot 用 Ja​​va 编写的应用程序。该应用程序需要加载与项目捆绑在一起的 .so 文件,我使用 JNA 来完成此任务。但是,JNA 加载程序似乎无法获取 .so 文件,并且应用程序无法启动。

我尝试从 IntelliJ 中运行应用程序,并使用“java -jar”运行打包的 .jar。.so 文件目前保存在 src/main/resources/linux-x86-64 中。我尝试将它们保存在不同的目录中,例如 src/main/resources/libs/linux-x86-64 并设置属性“jna.library.path”,但 JNA 仍然无法找到这些文件。

这是 JNA 的调试日志:

Trying (via loadLibrary) jnidispatch
Looking in classpath from sun.misc.Launcher$AppClassLoader@18b4aac2 for /com/sun/jna/linux-x86-64/libjnidispatch.so
Found library resource at jar:file:/home/dalivi/.m2/repository/net/java/dev/jna/jna/4.5.0/jna-4.5.0.jar!/com/sun/jna/linux-x86-64/libjnidispatch.so
Trying /tmp/jna--1339148563/jna4246531844315283838.tmp
Found jnidispatch at /tmp/jna--1339148563/jna4246531844315283838.tmp
Looking for library 'GTransTF'
Adding paths from jna.library.path: null
Trying libGTransTF.so
Adding system paths: [/usr/lib/x86_64-linux-gnu, /lib/x86_64-linux-gnu, /lib64, /usr/lib, /lib, /lib/i386-linux-gnu, /usr/lib/i386-linux-gnu, /usr/lib/x86_64-linux-gnu/libfakeroot]
Trying libGTransTF.so
Looking for version variants
Looking in classpath from sun.misc.Launcher$AppClassLoader@18b4aac2 for GTransTF
Found library resource at file:/home/dalivi/Workspace/java/geotransboot/target/classes/linux-x86-64/libGTransTF.so
Looking in /home/dalivi/Workspace/java/geotransboot/target/classes/linux-x86-64/libGTransTF.so
2019-04-25 12:43:38.032 ERROR 25897 --- [o-auto-1-exec-1] s.l.g.c.TransformationRestController     : Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: libCoreGTrans.so: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

我似乎确实在目录中找到了其中一个文件:libGTransTF.so,但在尝试查找与前一个文件位于同一目录中的文件libCoreGTrans.so时立即失败。

我应该提到,在 Windows 上,这工作得很好。JNA在“jna.library.path”指定的目录中查找相应的dll文件。

Pet*_*esh 5

Windows 的行为是在来自的目录中搜索依赖库.dll,因此当 jna 将库加载到内存中时,依赖库也会从那里加载。

如果您启动终端窗口并 cd 到该文件.so所在的目录并运行以下命令:

ldd ./libGTransTF.so
Run Code Online (Sandbox Code Playgroud)

它表明无法找到该库,libCoreGTrans.so那么您可以看到搜索顺序找不到该位置。

运行时链接加载器 ( ld.so) 使用一组关于在哪里查找库的决策。默认行为不包括找到该库的目录。

您可以在构建时向库添加一个选项,以在特定位置进行搜索以查找库。当您构建库时,您可以通过添加以下行在运行时.so来自的目录中进行搜索:

-Wl,-rpath,'$ORIGIN'
Run Code Online (Sandbox Code Playgroud)

到链接线。它需要填充常量值$ORIGIN,否则将不起作用,因此在 makefile 中正确使用可能有点棘手。这是在运行时解析的值。

如果您自己构建库,这一切都很好,但是如果您从其他地方获取库,或者您已经构建了它们并且不想重建它们,则可以使用诸如patchelf编辑搜索路径以.so添加其原始位置:

patchelf --set-rpath '$ORIGIN' libGTransTF.so
Run Code Online (Sandbox Code Playgroud)

然后当你运行时:

ldd ./libGTransTF.so
Run Code Online (Sandbox Code Playgroud)

它应该能够成功找到该libCoreGTrans.so库。