19

いくつかのネイティブ依存関係( LWJGL )を持つ Maven で管理されているプロジェクトがあります。

開発中はすべて正常に動作しますが、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.<clinit>(Sys.java:112)
        at org.lwjgl.opengl.Display.<clinit>(Display.java:132)
        at glaze.TestApp.start(TestApp.java:10)
        at glaze.TestApp.main(TestApp.java:31)

明らかに、ネイティブ ライブラリを手動でインストールして jar を実行することで動作させることができますjava -Djava.library.path=/path/to/libsが、それはユーザーに期待できることではありません。

関連する場合の pom.xml は次のとおりです: https://github.com/mikera/glaze/blob/master/pom.xml

ネイティブの依存関係を含む実行可能な .jar を作成し、ダブルクリックすると正常に実行されるように Maven をセットアップすることは可能ですか?

4

3 に答える 3

18

これは、jar にバンドルされているライブラリをロードdllするために使用していたコードです。so

ライブラリはリソースとして追加する必要があります。Maven を使用し、それらを次の階層に配置しました。

src/main/resources/lib/win-x86/<dlls for 32-bit windows>
src/main/resources/lib/linux-x86/<so for 32-bit linux>
src/main/resources/lib/linux-x86_64/<so for 64-bit linux>
src/main/resources/lib/linux-ia64/<so for 64-bit linux on itanium>

共有ライブラリは、プラットフォームの tmp ディレクトリに解凍され、解凍時に一時的な名前も付けられます。これは、複数のプロセスが実際に抽出された dll/so を共有せずに dll/so をロードできるようにするためです。これは、解凍すると、同じ名前の場合に既存の dll/so が上書きされる可能性があるためです (一部のプラットフォームでは、ファイルが置き換えられたときに非常に奇妙な動作が発生します)。

ファイルも設定済みに設定されています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) {
                }
            }
        }
    }
}

ライブラリは、 のインスタンスを作成してから、OS 固有の接頭辞と拡張子なしでNativeLoader呼び出すことによってロードされます。loadLibrary("thelibrary")

これは私たちにとってはうまくいきましたが、共有ライブラリを別のリソース ディレクトリに手動で追加してから、jar をビルドする必要があります。

このクラスの一部のコードは奇妙であるか時代遅れである可能性があることは認識していますが、これは私が数年前に書いたコードであり、非常にうまく機能していることを心に留めておいてください。

于 2012-08-20T15:12:19.517 に答える
1

ここで使用しようとしましたかmaven-assembly-plugin例は次のとおりです。

<build>
   <plugins>
      <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <configuration>
         <archive>
             <manifest>
                <mainClass>your.main.Class</mainClass>
             </manifest>
         </archive>
         <descriptorRefs>
             <descriptorRef>jar-with-dependencies</descriptorRef>
         </descriptorRefs>
         </configuration>
       </plugin>
   </plugins>
</build>

また、ネイティブの依存関係についてBundle-NativeCodeは、マニフェスト ファイルで使用することができます。http://wiki.osgi.org/wiki/Bundle-NativeCodeを参照してください。

Maven で生成するには、http maven-bundle-plugin: //felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.htmlも参照してください。

于 2012-08-20T11:34:14.643 に答える