Интеграция собственных системных библиотек с SBT

Что является хорошим способом интеграции различных задач SBT с собственными библиотеками (например, изJOGL, LWGL, или жеJCuda? В частности,

Is there a recommended way to include a native library in the run task? A discussion on the SBT mailing list suggests these possibilities:

Modify JavaOptions to include -Djava.library.path=<path to native libraries>, and then modify the run task to fork the JVM. (See this plugin for an example.) Use the SBT initialize setting to run code that calls System.setProperty(...) to configure java.library.path. Again, run must fork. Put the native libraries on the classpath before launching SBT.

The last one has the advantage that run need not fork, but the disadvantage that the configuration must be done outside SBT.

Can I automatically include native libraries in the Eclipse project generated by the sbteclipse plugin? It's possible to rewrite the .project file in a post-processing step. Is there example code? Is there a better way?

Can native libraries be included in the runnable Jar that is generated by a plugin such as sbt-assembly, sbt-onejar or sbt-proguard?

Я предполагаю, что нет прямой настройки SBT для нативных библиотек. Если бы что-то подобное существовало, могли ли вышеуказанные задачи прозрачно обрабатывать собственные библиотеки?

Ответы на вопрос(3)

которые я проводил в прошлом, есть только два способа загрузить нативные библиотеки: изменениеjava.library.path и используяSystem.loadLibrary (Я чувствую, что большинство людей делают это), или используяSystem.load с абсолютным путем.

Как вы уже упоминали, возиться сjava.library.path может раздражать с точки зрения настройки SBT и Eclipse, и я не думаю, что это можно сделать автоматически для исполняемого файла jar.

Так, что оставляетSystem.load. С точки зрения написания ваших собственных нативных библиотек вы можете сделать следующее:

Создайте задачу SBT, которая компилирует ваши исходные источники (с помощьюjavah а такжеgcc), получает полученные .so-файлы и любые .so-файлы, от которых он зависит, помещает их в jar (как ресурсы) в целевой каталог и добавляет путь к jar вunmanagedJars in Compile. Создайте метод Scala для загрузки библиотеки. Вместо звонкаSystem.loadLibrary, он будет использоватьClass.getResourceAsStream читать библиотеку,File.createTempFile чтобы записать это где-нибудь в файловой системе, иSystem.load чтобы загрузить его в JVM. Теперь вместо звонкаSystem.loadLibrary как и раньше, звониMyClasspathJniLoader.loadLibrary.

Это будет работать с SBT run, Eclipse и исполняемыми файлами jar без какой-либо дополнительной настройки (хотя я не знаю, как proguard знает, какие ресурсы включить).

Что касается сторонних собственных библиотек, которые уже написаны, некоторые из них, например, Jblas уже использую этот подход "полная банка". Если они ожидают, что вы настроитеjava.library.path а потом они зовутSystem.loadLibrary когда им захочется, тебе нужно сделать что-нибудь волшебное, чтобы заставить это работать.

Я не пробовал это, но это решение могло бы работать:

Используйте аналогичную задачу SBT, чтобы поместить все библиотеки по их собственному пути в банку в качестве ресурсов, и поместите эту банку в clsaspath. Создайте метод Scala, который принимает функцию и список имен библиотек, создает временный каталог, считывает эти библиотеки из ресурсов jar в файлы в временном каталоге, добавляет временный каталог вjava.library.path, вызывает переданную функцию и, наконец, возвращаетjava.library.path назад к тому, что было раньше. При первом вызове в нативную библиотеку (когда она предположительно будет статически инициализирована и создастSystem.loadLibrary call), оберните этот конкретный вызов в вашем методе в список библиотек, которые он будет загружать. Таким образом, когда он вызываетSystem.loadLibrary, все его библиотеки будут наjava.library.path и будет успешно загружен.

Очевидно, что это раздражает, так как вам нужно вручную инициализировать стороннюю библиотеку перед ее использованием, но кажется более целесообразным обернуть все точки инициализации (ваши основные функции и инициализации теста), чем сделать так, чтобы все ваши инструменты были установленыjava.library.path правильно. И это может быть даже проще, чем если у вас уже есть собственный уровень абстракции над сторонней библиотекой, так что на самом деле вам нужно обернуть только одну точку инициализации.

Если это кажется реалистичным решением, я могу добавить больше информации о задаче SBT или методах оболочки Scala, если вы не уверен

Предположим, что нативные библиотеки хранятся в Lib_extra каталог

добавить JN в libraryDependencies:

libraryDependencies ++ = Seq ("net.java.dev.jna"% "jna-platform"% "4.1.0")

добавить этот код в build.sbt:

unmanagedResourceDirectories в Compile + = baseDirectory.value / "lib_extra"

includeFilter in (Compile, unmanagedResourceDirectories): = " .Dll,.так"

/lib/*.jnilib в течениеsbt test.

[error] java.lang.UnsatisfiedLinkError: Fatal execution error, caused by no jniortools in java.library.path

Вы можете использовать следующий код вместоSystem.loadLibrary("jniortools").

new File("lib").listFiles().map(_.getAbsolutePath).filter(_.endsWith("jniortools.jnilib")).foreach(System.load)

ВАШ ОТВЕТ НА ВОПРОС