переносимый оператор для загрузки библиотеки JNI из другого каталога с использованием относительного пути?

Существует ли независимый от платформы оператор Java для загрузки собственной библиотеки из каталога, отличного от исходного кода Java? Я бы хотел использовать что-то вроде этого:

public class HelloWorld {
    static {
        System.loadLibrary("../some_project/HelloWorld");
    }

    public static native void print();
}

Проблема в том, что System.loadLibrary () не поддерживает разделители каталогов в аргументе пути. Кроме того, System.load (), к сожалению, требует абсолютного пути, что не только означает, что я не могу указать относительный каталог, как указано выше (что я бы хотел сделать), но также требует, чтобы аргумент включал, например, предыдущий Расширения «lib» и «.so» в имени библиотеки JNI в системе Linux.

Есть ли стандартный способ справиться с этим? Если возможно, я бы не хотел писать кучу платформенно-зависимого кода Java, просто чтобы создать правильное имя библиотеки JNI.


person jvm_update    schedule 21.05.2012    source источник
comment
Разве не было бы более стабильным, если бы путь был относительно, например, ваш файл .jar, а не текущий каталог. Это обязательно вызовет проблемы в долгосрочной перспективе, если текущий каталог отличается (например, из-за ярлыка на рабочем столе)   -  person a_horse_with_no_name    schedule 22.05.2012
comment
Это хороший момент, спасибо, что указали на это. Я не знаю, как использовать путь относительно файла .jar, но, чтобы не задавать второй вопрос в комментарии, я просто сделаю ссылку на несколько других вопросов о stackoverflow, которые кажутся полезными: stackoverflow.com/questions/2837263/ stackoverflow.com/questions/5053150/ stackoverflow.com/questions/779650/   -  person jvm_update    schedule 24.05.2012
comment
Первый квестин (тот, который использует getProtectionDomain()) - единственно правильный ответ на эту проблему.   -  person a_horse_with_no_name    schedule 24.05.2012


Ответы (2)


Я считаю, что вы ищете систему .mapLibraryName, который обычно используется ClassLoader.findLibrary. Например:

File lib = new File("../some_project/" + System.mapLibraryName("HelloWorld"));
System.load(lib.getAbsolutePath());

Это будет использовать libHelloWorld.so в Linux и HelloWorld.dll в Windows. Имейте в виду, что некоторые операционные системы поддерживают несколько расширений, а mapLibraryName может поддерживать только одно, по замыслу. Мне известны MacOS (.dylib в основном и .jnilib для устаревших версий) и AIX (.a и .so).

person Brett Kail    schedule 21.05.2012
comment
Спасибо! Это то, что я искал. Я просто попробовал, и он отлично работает. Просто для справки для всех, кто это читает, System.load () требует абсолютного имени пути, поэтому каталог необходимо сделать абсолютным и добавить косую черту в конце, например, с кодом: new java.io.File (.. / некоторый_проект /). getCanonicalPath () + / - person jvm_update; 22.05.2012
comment
Я обновил ответ, включив getAbsolutePath, спасибо. - person Brett Kail; 22.05.2012
comment
+1 mapLibraryName - это кусок мозаики, о котором я ничего не знал - person David Heffernan; 22.05.2012

Ну, как вы ясно объяснили, вы не можете использовать loadLibrary. Итак, остается load. Но для этого нужен абсолютный путь. Итак, преобразуйте относительный путь в абсолютный путь, используя ваши предпочтительные служебные функции пути к файлу, и передайте его load. Это может показаться неудобным, но это гораздо надежнее, чем полагаться на капризы путей поиска в библиотеках.

person David Heffernan    schedule 21.05.2012
comment
Как расширить его до абсолютного пути? Что еще более важно, как можно переносить загрузку? Библиотека будет иметь три разных имени файла на трех разных платформах: HelloWorld.dll (Windows), libHelloWorld.so (Linux) и libHelloWorld.jnilib (Mac OS X). Какая строка (строки) кода Java автоматически выберет соответствующее имя на соответствующей платформе без жесткого кодирования оператора switch в код Java? - person jvm_update; 22.05.2012
comment
Что ж, относительный путь относится к чему-то. Так что поместите это что-то перед относительной частью, и вы получите свой абсолютный путь. Что касается расширения, я не знаю, есть ли что-нибудь встроенное, но оно должно быть достаточно простым для обнаружения платформы и переключения. - person David Heffernan; 22.05.2012
comment
Моя цель - иметь возможность переносить приложение на новую платформу без необходимости перекомпилировать Java-часть приложения. То есть скомпилированный код Java должен быть переносимым. К сожалению, явная проверка того, в какой операционной системе работает код, не зависит от платформы. - person jvm_update; 22.05.2012
comment
Затем найдите способ использовать loadLibrary в этом случае - person David Heffernan; 22.05.2012
comment
Это именно то, о чем спрашивал исходный вопрос, как это сделать. - person jvm_update; 22.05.2012
comment
Тогда продолжайте и используйте loadLibrary. Просто живите с ограничением на расположение файлов библиотеки. - person David Heffernan; 22.05.2012