===== 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. {{ :courses:b6b36pjv:tutorials:11:jni.png?direct&700 |}} 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ů: - 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. - 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). - 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); - Implementace deklarovaných funkcí v C: * V NetBeans zvolte //New Project// -> //C/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 #include #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { printf("Hello World!\n"); return; } - 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). - 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. Dokumentace JNI API: [[https://docs.oracle.com/javase/8/docs/technotes/guides/jni/index.html]]