2012-05-25 12 views
31

Co to dobry sposób, aby zintegrować różne zadania SBT z bibliotek natywnych (na przykład te z JOGL, LWGL lub JCuda? KonkretnieIntegracja rodzime biblioteki systemowe z SBT

  1. istnieje zalecany sposób obejmują natywne biblioteki w zadaniu run dyskusja na liście mailingowej SBT sugeruje te możliwości?

    Ten ostatni ma tę zaletę, że run nie potrzebuje rozwidlenia, ale ma tę wadę, że konfigurację należy wykonać poza SBT.

  2. Czy mogę automatycznie włączyć biblioteki natywne do projektu Eclipse wygenerowanego przez wtyczkę sbteclipse? Możliwe jest rewrite the .project file in a post-processing step. Czy istnieje przykład kodu? Czy istnieje lepszy sposób?

  3. Czy biblioteki rodzime być zawarte w runnable słoik, który jest generowany przez wtyczkę taką jak sbt-assembly, sbt-onejar lub sbt-proguard?

Zakładam, że nie ma bezpośredniego ustawienia SBT dla bibliotek natywnych. Jeśli coś takiego istnieje, czy powyższe zadania mogą obsługiwać biblioteki macierzyste w przejrzysty sposób?

Odpowiedz

28

Z badań robiłem w przeszłości, istnieją tylko dwa sposoby, aby uzyskać natywne biblioteki załadowane: Modyfikacja java.library.path i obsługiwanie System.loadLibrary (czuję się jak większość ludzi to zrobić), lub stosując System.load bezwzględną ścieżkę.

Jak wspomnieliście, mieszanie się z java.library.path może być denerwujące pod względem konfiguracji SBT i Eclipse, i nie sądzę, że można to zrobić automatycznie dla pliku wykonywalnego.

Pozostawia to System.load. Jeśli chodzi o pisanie własnych bibliotek natywnych, co można zrobić, to:

  • Utwórz zadanie SBT że kompiluje swoje rodzime źródła (javah i gcc), bierze otrzymany .so plików oraz wszelkie pliki .so to zależy on, umieszcza je w słoiku (jako zasoby) w katalogu docelowym i dodaje ścieżkę do słoika do unmanagedJars in Compile.
  • Utwórz metodę Scala, aby załadować bibliotekę. Zamiast wywoływania System.loadLibrary, będzie używał Class.getResourceAsStream do odczytu biblioteki, File.createTempFile, aby zapisać go gdzieś w systemie plików, i System.load, aby załadować go do JVM.
  • Teraz zamiast dzwonić pod numer System.loadLibrary, zadzwoń pod numer MyClasspathJniLoader.loadLibrary.

To zadziała z SBT run, Eclipse i wykonywanymi słojami bez dodatkowej konfiguracji (chociaż nie wiem, w jaki sposób proguard wie, które zasoby uwzględnić).

Co do bibliotek natywnych stron trzecich, które zostały już napisane, niektóre z nich, takie jak jblas, już używają tego "grubego słoika". Jeśli oczekują, że skonfigurujesz java.library.path, a następnie zadzwonią pod numer System.loadLibrary, kiedy będą mieli na to ochotę, musisz zrobić trochę magii, aby wykonać tę pracę.

nie próbowałem tego, ale to rozwiązanie może działać:

  • użyć podobnego zadania SBT umieścić wszystkich bibliotekach na ich rodzimej ścieżce do słoika jako zasobów, i umieścić ten słoik na clsaspath.
  • Utwórz metodę Scala, która przyjmuje funkcję i listę nazw bibliotek, tworzy katalog tymczasowy, odbiera te biblioteki z zasobów słoika do plików w katalogu tymczasowym, dodaje katalog tymczasowy do java.library.path, wywołuje przekazaną funkcję, i na koniec cofa java.library.path z powrotem do tego, co było wcześniej.
  • Po pierwszym wywołaniu w bibliotece macierzystej (gdy prawdopodobnie będzie inicjować statycznie i wykonać wywołanie System.loadLibrary), należy zawinąć to konkretne wywołanie w swojej metodzie z listą bibliotek, które będzie ładować. W ten sposób, gdy zadzwoni System.loadLibrary, wszystkie jego biblioteki będą na java.library.path i zostaną załadowane pomyślnie.

Oczywiście jest to denerwujące, ponieważ trzeba ręcznie zainicjować bibliotekę stron trzecich przed jej użyciem, ale wydaje się bardziej możliwe zawijanie wszystkich punktów inicjalizacji (głównych funkcji i inicjalizacji testów), niż uzyskanie wszystkich narzędzi do prawidłowego ustawienia java.library.path. I może być jeszcze łatwiejsze, jeśli masz już własną warstwę abstrakcji nad biblioteką osób trzecich, tak naprawdę jest tylko jeden punkt inicjalizacji, który musisz zawinąć.

Jeśli to wydaje się być realistycznym rozwiązaniem, mogę dodać więcej szczegółów na temat zadania SBT lub metod pakowania Scala, jeśli jesteś zdezorientowany.

0

Pod Osxem, jeśli masz problemy z ładowaniem natywnych bibliotek w /lib/*.jnilib podczas sbt test.

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

Można użyć następującego kodu zamiast System.loadLibrary("jniortools").

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

Istnieje prosty sposób.

Załóżmy, że natywne biblioteki przechowywane w lib_extra katalogu

  1. dodać JNA do libraryDependencies:

    libraryDependencies ++ = seq ("net.java.dev.jna" % " jna-platforma "% " 4.1.0 ")

  2. dodać ten kod do kompilacji.SBT:

    unmanagedResourceDirectories w kompilacji + = baseDirectory.value/"lib_extra"

    includeFilter w (kompilacji unmanagedResourceDirectories): = "dll, .so"