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