Volání C z Javy (Java Native Interface)

javah je v ucebne v adresari /opt/jdk1.8.0_144/bin
javah je od verze JDK 8 nahrazen voláním “javac -h …”

Součástí Java platformy je rozhraní JNI (Java Native Interface), které umožňuje propojit kód běžící na virtuálním stroji Javy s nativními programy a knihovnami napsanými v jiných programovacích jazycích (např. C). Hlavními výhodami jsou zvýšení výkonu v některých low-level úlohách (např. Math.sqrt(double a)) a umožnění komunikace s hardwarovými zařízeními (Bluetooth, apod.). Nevýhodou je především ztráta platformní nezávislosti, protože takový program využívá knihovny zkompilované pro daný operační systém.

Implementace nativní knihovny a propojení s Javou je znázorněno na obrázku výše. Příklad ilustruje vytvoření C knihovny, která vypisuje text “Hello World!” a její volání z Java aplikace. Celý proces implementace je možné shrnout do několika kroků:

  1. Vytvoření třídy s deklaracemi nativních metod:

class HelloWorld {
 
    static { /* statický inicializátor */
        System.loadLibrary("HelloWorld"); /* načtení dynamické knihovny vytvořené v jazyku C */
  //    System.load("/import/users/mudromar/libhelloWorld.so"); // druha moznost nacteni souboru bez zadavani java.library.path
    }
 
    private native void print(); /* deklarace nativní metody */
 
    public static void main(String[] args) {
        new HelloWorld().print();
    }
}

  • metoda loadLibrary(String libname) slouží k načtení externí systémové knihovny, parametr libname zastupuje cestu ke knihovně,
  • příkazy uvnitř statického inicializátoru (static { }) se provádí po zavedení třídy do paměti, ještě před voláním konstruktoru ⇒ nejprve se načte externí knihovna a až poté se zpracovává kód třídy,
  • native je klíčové slovo pro označení nativní metody, tj. metody vytvořené v jazyku C, kterou budeme volat.
  1. Kompilace Java programu:
    • zkompilujte vytvořenou třídu: buď v NetBeans kliknout pravým tlačítkem na název projektu a vybrat “Clean and Build” nebo externím nástrojem javac,
    • v podadresáři “build\classes” projektového adresáře se vytvoří bytecode (.class).
  2. Generování hlavičkového souboru:
    • aplikujte nástroj javah (součástí JDK, typicky v C:\Program Files\Java\jdk\bin) na bytecode Java třídy ke generování C hlavičkového souboru (.h) s deklaracemi nativních funkcí. Název bytecode souboru zadejte bez přípony .class:
      javah -jni HelloWorld
    • ve vytvořeném hlavičkovém souboru je nejdůležitější vygenerovaná deklarace C funkce, která je propojena s Java nativní metodou:
      JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);
  3. Implementace deklarovaných funkcí v C:
    • V NetBeans zvolte New ProjectC/C++ Dynamic Library.
    • Vytvořený projekt je třeba propojit s JNI knihovnami:
      • v NetBeans klikněte pravým tlačítkem na název projektu a zvolte Properties,
      • na záložce C Compiler vyplňte do Include Directories cesty k JNI (typicky C:/Program Files/Java/jdk/include a C:/Program Files/Java/jdk/include/win32),
      • na stejné záložce ještě vyplňte Additional Options hodnou:
        -Wl,--add-stdcall-alias -mno-cygwin -shared -m32 -Wall -pedantic
        • -Wl,–add-stdcall-alias nastavuje pro linker přepínač –add-stdcall-alias, který zaručí vytvoření knihovny pro Windows,
        • -mno-cygwin zaručí vytvoření knihovny nezávislé na Cygwin,
        • -shared indikuje vytvoření dynamické knihovny namísto spustitelného souboru (pokud nepoužíváte NetBeans nebo jste nevytvořili C/C++ Dynamic Library),
        • -m32 indikuje vytvoření 32b knihovny (má význam jen pokud používáte 64b GCC a 32b JDK),
        • -Wall -pedantic zaručí výpis všech varovných hlášení a důslednou kontrolu zdrojového kódu podle striktní normy.
    • Do vytvořeného projektového adresáře nakopírujte vygenerovaný hlavičkový soubor a propojte ho s projektem (klikněte pravým tlačítkem myši na Source Files a vyberte Add Existing Item).
    • Klikněte pravým tlačítkem myši na Source Files, vyberte New a poté C Source File.
    • Do nově vytvořeného souboru přidejte #include na JNI, na vytvořený hlavičkový soubor a implementujte deklarované funkce:
      #include <jni.h>
      #include <stdio.h>
      #include "HelloWorld.h"
       
      JNIEXPORT void JNICALL
      Java_HelloWorld_print(JNIEnv *env, jobject obj) {
          printf("Hello World!\n");
          return;
      }
  4. Kompilace C programu a generování nativní knihovny:
    • v NetBeans klikněte pravým tlačítkem myši na název projektu a vyberte Clean and Build,
    • v podadresáři dist projektového adresáře se vytvoří nativní dynamická knihovna (ve Windows .dll, v Unix .so).
  5. Spuštění programu java interpretrem
    • překopírujte vytvořenou knihovnu (.dll nebo .so) do Java projektového adresáře nebo do adresáře kde je umístěn spustitelný soubor Java aplikace,
    • bude-li knihovna v jiném adresáři, musíte definovat cestu v metodě loadLibrary(),
    • spusťte Java aplikaci a na obrazovce shlédněte výpis textu „Hello World!“ definovaný v C.
courses/b0b36pjv/tutorials/11/java_native_interface.txt · Last modified: 2019/05/06 13:39 by mudromar