使用Maven将runnable .jar中的本机依赖项捆绑在一起

我有一个在Maven中管理的项目,它有一些本机依赖项 ( LWJGL )。

一切都在开发中工作正常,但现在我想设置Maven,以便它将构建一个可以重新分发的可运行的.jar文件。 特别是,我希望用户可以非常轻松地运行应用程序,而无需使用库路径或解压缩本机库等。

目前我能够构建一个包含所有依赖项的.jar文件,但如果我运行它(不出所料)我得到一个不满意的链接错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no lwjgl in java.libr ary.path at java.lang.ClassLoader.loadLibrary(Unknown Source) at java.lang.Runtime.loadLibrary0(Unknown Source) at java.lang.System.loadLibrary(Unknown Source) at org.lwjgl.Sys$1.run(Sys.java:73) at java.security.AccessController.doPrivileged(Native Method) at org.lwjgl.Sys.doLoadLibrary(Sys.java:66) at org.lwjgl.Sys.loadLibrary(Sys.java:95) at org.lwjgl.Sys.(Sys.java:112) at org.lwjgl.opengl.Display.(Display.java:132) at glaze.TestApp.start(TestApp.java:10) at glaze.TestApp.main(TestApp.java:31) 

显然,我可以通过手动安装本机库并使用java -Djava.library.path=/path/to/libs运行jar来使其工作,但这不是我期望用户做的事情。

这是pom.xml,如果它是相关的: https : //github.com/mikera/glaze/blob/master/pom.xml

可以设置Maven,以便它创建一个包含本机依赖项的可运行.jar,并在双击时成功运行?

这是我用来加载jar中捆绑的dll或类库的一些代码。

必须将库添加为资源。 我们使用maven并将它们放在这个层次结构中:

 src/main/resources/lib/win-x86/ src/main/resources/lib/linux-x86/ src/main/resources/lib/linux-x86_64/ src/main/resources/lib/linux-ia64/ 

共享库将解压缩到平台的tmp目录,并在解压缩时具有临时名称。 这是为了让几个进程加载dll / so而不共享实际提取的dll /,因为如果具有相同的名称,解包可以覆盖现有的(当替换文件时在某些平台上有非常奇怪的行为)。

该文件也设置为设置deleteOnExit但在Windows AFAIK上不起作用。

NativeLoader.java

 public class NativeLoader { public static final Logger LOG = Logger.getLogger(NativeLoader.class); public NativeLoader() { } public void loadLibrary(String library) { try { System.load(saveLibrary(library)); } catch (IOException e) { LOG.warn("Could not find library " + library + " as resource, trying fallback lookup through System.loadLibrary"); System.loadLibrary(library); } } private String getOSSpecificLibraryName(String library, boolean includePath) { String osArch = System.getProperty("os.arch"); String osName = System.getProperty("os.name").toLowerCase(); String name; String path; if (osName.startsWith("win")) { if (osArch.equalsIgnoreCase("x86")) { name = library + ".dll"; path = "win-x86/"; } else { throw new UnsupportedOperationException("Platform " + osName + ":" + osArch + " not supported"); } } else if (osName.startsWith("linux")) { if (osArch.equalsIgnoreCase("amd64")) { name = "lib" + library + ".so"; path = "linux-x86_64/"; } else if (osArch.equalsIgnoreCase("ia64")) { name = "lib" + library + ".so"; path = "linux-ia64/"; } else if (osArch.equalsIgnoreCase("i386")) { name = "lib" + library + ".so"; path = "linux-x86/"; } else { throw new UnsupportedOperationException("Platform " + osName + ":" + osArch + " not supported"); } } else { throw new UnsupportedOperationException("Platform " + osName + ":" + osArch + " not supported"); } return includePath ? path + name : name; } private String saveLibrary(String library) throws IOException { InputStream in = null; OutputStream out = null; try { String libraryName = getOSSpecificLibraryName(library, true); in = this.getClass().getClassLoader().getResourceAsStream("lib/" + libraryName); String tmpDirName = System.getProperty("java.io.tmpdir"); File tmpDir = new File(tmpDirName); if (!tmpDir.exists()) { tmpDir.mkdir(); } File file = File.createTempFile(library + "-", ".tmp", tmpDir); // Clean up the file when exiting file.deleteOnExit(); out = new FileOutputStream(file); int cnt; byte buf[] = new byte[16 * 1024]; // copy until done. while ((cnt = in.read(buf)) >= 1) { out.write(buf, 0, cnt); } LOG.info("Saved libfile: " + file.getAbsoluteFile()); return file.getAbsolutePath(); } finally { if (in != null) { try { in.close(); } catch (IOException ignore) { } } if (out != null) { try { out.close(); } catch (IOException ignore) { } } } } } 

通过创建NativeLoader的实例然后通过调用loadLibrary("thelibrary")来加载库,而不使用特定于os的前缀和扩展。

这对我们很有用,但您必须手动将共享库添加到不同的资源目录,然后构建jar。

我意识到这个类中的一些代码可能很奇怪或已经过时但是请记住这是我几年前写的代码并且它一直运行得很好。

您是否尝试使用maven-assembly-plugin这是一个示例:

    maven-assembly-plugin    your.main.Class    jar-with-dependencies      

对于您的本机依赖项,​​您可能希望在清单文件中使用Bundle-NativeCode 。 请参阅http://wiki.osgi.org/wiki/Bundle-NativeCode 。

您还可以查看maven-bundle-plugin : http : //felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html以使用Maven生成它。

这是你的pom.xml需要的插件,用你提到的所需运行参数来运行你的构建:

   org.codehaus.mojo exec-maven-plugin 1.6.0  java  -Djava.library.path=target/natives -classpath  my.main.package.MainClass    

然后使用运行您的LWJGL程序

 mvn exec:exec