Ответ 1
Это код, который я использовал для загрузки библиотек 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, так как распаковка может перезаписывать существующие, если они имеют одинаковое имя (с очень странным поведением на некоторых платформах при замене файла).
В файле также установлено значение deleteOnExit
, но это не работает в окнах 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.
Это сработало для нас, но вам придется добавлять общие библиотеки вручную в разные каталоги ресурсов, а затем создавать банку.
Я понимаю, что некоторый код в этом классе может быть странным или устаревшим, но не забывайте, что это код, который я написал несколько лет назад, и он работает очень хорошо.