4. diel - JNI - Príklad v Eclipse s Makefile
V minulom tutoriále o prácu s Java Native Interface sme si vytvorili prvú JNI aplikáciu. Nepoužili sme k tomu IDE. Dnes si ukážeme ako aplikáciu vytvoriť za pomoci IDE Eclipse s balíčkom CDT. Budeme si pomáhať známym súborom Makefile.
Prečo toto riešenie? Predvedie nám ako možno v Eclipse CDT vykonávať kompiláciu / linkovanie ( "tzv. Build") podľa konfiguračných parametrov. To býva u C / C ++ projektov dosť často vítané a požadované. Zaiste viete, že natívny kompilátory umožňujú zásadným spôsobom ovplyvňovať efektivitu z buildovaných programov cez nastavenie parametrov. To možno úspešne využiť v Eclipse CDT. Táto možnosť chýba u interpretovaných jazykov, kde za nás všetko rieši VM, ktoré sa moc konfigurovať nedajú.
Ak ste si vyskúšali predchádzajúci postup, kde sme vytvárali * .dll bez IDE, potom možno budete zdesení prílišnou komplikovanosťou pri práci s IDE a pochopíte, prečo niektorí programátori stále odmietajú výhody IDE. Ono to skutočne s IDE je zložitejšia, ale získate tým vďaka GUI jednoznačne prehľad v projekte v navigátora (project explorer). Ďalšou výhodou IDE je značné zjednodušenie pri vytváraní samospustitelného java programu (tvz. Runnable jar). V príkazovom riadku to možno samozrejme tiež, ale je to pracnejšie a zložitejšie (tvorba meta informácií pre META-INF), to všetko za nás IDE, konkrétne Eclipse, prípadne v kombinácii s Maven, vyrieši.
Osnova postupu
Vykonávaný postup je veľmi podobný s postupom v predchádzajúcom dieli.
- Vytvoríme Java projekt vrátane spúšťací triedy (.java) a skompilujeme (.class)
- Prekonvertuje Java project do C / C ++ projektu
- Vytvoríme konfiguračný súbor buildu Makefile a v projekte vytvoríme hlavičkový súbor (* .h)
- Z header filu (hlavičkového súboru) vytvoríme source file (zdrojový súbor * .c)
- Daný zdrojový súbor skompilujeme a nalinkuje, vznikne * .dll súbor
- Upravíme spúšťacie Java triedu, aby sme načítali natívne knižnicu
- Zavoláme natívne metódy z Javy
1 - Tvorba Java projektu
Ako prvý krok samozrejme skontrolujeme perspektívu. Musí byť nastavená Java. Ďalej vytvoríme Java projekt, ktorý si nejako pomenujeme. Vytvoríme spúšťací triedu bez balíčka a doplníme telo spúšťacie metódy + navrhneme natívne metódy. Program spustíme a dole v konzole si skontrolujeme výstup.
public class ProgramJNI { native void metodaTisk(); native int ziskejInt(); native int zvysIntDeset(int cislo); public static void main (String [] args) { System.out.println("Testovací vypis JNI v Eclipse s makefile"); } }
Čo danej metódy vlastne robia? Prvá metóda nemá návratový typ, je typu void a teda nič z nej nezískame do programu Javy. Prakticky opäť testovacia metóda, kedy kontrolu funkčnosti vykonáme cez výstup do konzoly. Druhá metóda má návratový typ int, čo znamená, že natívny metóda nám prenesie hodnotu integer z natívne časti programu do interpretované časti programu. Tretia metóda nielen, že má ako návratový typ integer, ale má aj parameter typu integer. To znamená, že interpretovaná časť do natívnej časti integer pošle a natívne časť ho interpretované časti vráti. Česky a matematicky povedané, pošleme tam číslo a to číslo zvýšime o 10. Nejde o nijak zložitú časť.
2 - prekonvertovaná projektu do C / C ++
Ako ďalší krok vykonáme konverziu z Java Projektu na C / C ++ Projekt. K tomu samozrejme nestačí len zmeniť perspektívu. Konverziu vykonáme podľa obrázku. Označíme projekt, ktorý chceme skonvertovať, a vyvoláme Popup okno -> new -> other.
Objaví sa dialógové okno New a vyberieme C / C ++. Zvolíme Convert to a C / C ++ Project.
Nastavíme vlastnosti projektu. Zvolíme projekt, vyberieme C Projekt, zvolíme Makefile project a typ kompilátora v našom prípade MinGW.
Môžeme si všimnúť zmien Project exploreru v projekte. Projekt sa překonvertoval. Samozrejme automaticky došlo k zmene perspektívy na C / C ++. Len tak mimochodom, rovnakým spôsobom možno v Eclipse konvertovať Java Projekty do štruktúry Maven.
3 - Tvorba konfiguračného a hlavičkového súboru
Teraz si vytvoríme adresár \ JNI. Do tohto adresára umiestnime súbory potrebné pre natívny časť (header file, source file, Makefile, dll). Samozrejme možno adresár pomenovať ako sa nám zachce, ale je nutné na to brať ohľad a riešení tomu prispôsobiť. File -> New -> Folder -> objaví sa dialóg, kde vyberieme projekt do ktorého daný adresár vložíme, a tiež adresár pomenujeme "JNI" v časti Folder name. Ak všetko nastavíme správne, zviditeľní sa mám tlačidlo Finish a my ho potvrdíme.
Do tohto adresára vytvoríme Makefile (súbor s menom Makefile). Označíme daný adresár a opäť vyvoláme Popup okno. Vyberieme cestu New -> File -> a objaví sa nám opäť dialógové okno. Zvolíme adresár, kde sa má vytvoriť, a do File name vložíme "Makefile".
(Java 9,8,7,6, ...) Do novovzniknutého súboru vložíme tieto definície:
# Definujeme promenou pro classpath CLASS_PATH = ../bin # Definujeme virtualni cestu pro .class v adresari \bin vpath %.class $(CLASS_PATH) # $* zde nastavujime co vlastne chceme a to ze chceme vytvorit header file ProgramJNI.h : ProgramJNI.class javah -classpath $(CLASS_PATH) $*
Java 10,11 [18.9], 12 [19.3], ...: Pretože, nám došlo k zmene z
javah -jni ProgramJNI.class
na javac -h . ProgramJNI
,
tak musíme upraviť konfiguračný súbor Makefile tak, aby nám fungoval. Do
novo vzniknutého súboru vložíme tieto definície:
# Definujeme promenou pro classpath CLASS_PATH = ../src/ koncovka = .java # Definujeme virtualni cestu pro .java v adresari \src vpath %.java $(CLASS_PATH) # $* zde nastavujime co vlastne chceme a to ze chceme vytvorit header file ProgramJNI.h : ProgramJNI.java javac -h . $(CLASS_PATH)$*$(koncovka)
Teraz nás čaká prevedení tvz. "Buildu". Aj keď o "build" sa v tomto prípade nejde, pretože účelom tohto nastavenia je vytvorenie hlavičkového súboru. Najskôr vytvoríme target (označuje typ buildu), označíme Makefile a vyvoláme Popupokno, kde vyberieme možnosť MakeTargets -> Build.
V dialógovom okne Make Target zvolíme "Add ...". Ako Target Name vložíme meno požadovaného hlavičkového súboru (header file) a hlavne je nutné nastaviť Build Command, kde definujeme súbor make v danom kompilátora. Ten sa volá mingw32-make a nachádza sa v C: \ MinGW64 \ mingw64 \ bin. Potvrdíme OK.
Teraz sme si vytvorili náš prvý Makefile, ktorý akurát vykoná vytvorenie ProgramJNI.h, tvz. header file, ktorý potrebujeme pre náš zdrojový súbor.
(Pozn. Java 9,8,7, ..) Než spustíme náš Makefile, uistite sa, že
projektu existuje adresár \bin\
, ktorý obsahuje nami
skompilovanú javovskou triedu (tzn. *.class
).
Klikneme na náš projekt v Project exploreru a stlačíme Shift + F9 (alebo
v menu Project -> Make Target -> Build ...). Objaví sa okno Make Targets
a my zvolíme Build.
Pozn. Niekedy sa vám môže zdať, že bude chýbať špecifikácie Location, v
mojom prípade JNI. I keď tam nebude, tak by sa build mal vykonať.
Alternatívne môžete manuálne daný adresár upraviť v adresári projektu v
súbore .cproject
, kde na riadku:
<target name="ProgramJNI.h" path="jni" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
doplníte path. To môžete urobiť pre akýkoľvek bod buildu.
Po vykonaní by ste mali vidieť výpis v konzole bez Warning + errorov a
taktiež si v Project exploreru v adresári jni/
všimnite
vzniknutého ProgramJNI.h
:
4 - Tvorba zdrojového súboru C / C ++
Ďalej vytvoríme nový súbor "ProgramJNI.c". Vytvára sa identickým spôsobom ako sme vytvorili súbor Makefile, až na to, že si nevyberieme file, ale source file. Najskôr označíme adresár \ JNI \, potom klikneme v menu File -> New -> Source File, ktorý bude slúžiť ako zdrojový súbor.
V dialógu definujeme jeho meno a zvolíme Finish. Do daného zdrojového súboru opätovne umiestnime hlavičky metód z hlavičkového súboru. Doplníme parametre metód. Pridáme importované knižnice a hlavičky. Nakoniec doplníme i tela metód. Pre čitateľov znalých C a Java sú telá metód triviálne.
#include <jni.h> #include <stdio.h> #include "ProgramJNI.h" JNIEXPORT void JNICALL Java_ProgramJNI_metodaTisk(JNIEnv *env, jobject obj){ printf("Zde je vystup pro zavolanou nativni metodou \n"); } JNIEXPORT jint JNICALL Java_ProgramJNI_ziskejInt(JNIEnv *env, jobject obj){ jint hodnota =846; return hodnota; } JNIEXPORT jint JNICALL Java_ProgramJNI_zvysIntDeset(JNIEnv *env, jobject obj , jint cislo){ jint dllCislo = cislo +10; return dllCislo; }
5 - Kompilácia do * .dll súboru
Teraz prichádza trochu komplikovanejšia časť. Počítam, že ste podľa prvého dielu skopírovali jni.ha jni_md.h do definovaného adresára. Teraz nás čaká prevedenie buildu (vytvorenie zdieľané knižnice) za pomocou Makefile. Starý Makefile premenujeme a vytvoríme nový podľa postupu v bode 3.
Doplníme ho nastavením pre kompiláciu / linkovanie. Makefile nie je predmetom seriálu o JNI a preto si ho tu vysvetľovať nebudeme. Pre Java vývojárov to nie je zásadný a v nasledujúcej kapitole predvediem používanie IDE Eclipse bez Makefile.
Java 9,8,7,6 ...:
# Definujeme promenou pro classpath CLASS_PATH = ../bin # Definujeme virtualni cestu pro .class v adresari \bin vpath %.class $(CLASS_PATH) all : ProgramJNI.dll # $@ provadime linkovani ProgramJNI.dll : ProgramJNI.o x86_64-w64-mingw32-gcc -Wl,--add-stdcall-alias -shared -o $@ $< # $@ provadime kompilaci ProgramJNI.o : ProgramJNI.c ProgramJNI.h x86_64-w64-mingw32-gcc -c $< -o $@ # $* ProgramJNI.h : ProgramJNI.class javah -classpath $(CLASS_PATH) $* clean : rm ProgramJNI.o ProgramJNI.dll
Java 10,11 [18.9], 12 [19.3], ...:
# Definujeme promenou pro classpath CLASS_PATH = ../src/ koncovka = .java # Definujeme virtualni cestu pro .java v adresari \src vpath %.java $(CLASS_PATH) all : ProgramJNI.dll # $@ provadime linkovani ProgramJNI.dll : ProgramJNI.o x86_64-w64-mingw32-gcc -Wl,--add-stdcall-alias -shared -o $@ $< # $@ provadime kompilaci ProgramJNI.o : ProgramJNI.c ProgramJNI.h x86_64-w64-mingw32-gcc -c $< -o $@ # $* ProgramJNI.h : ProgramJNI.java javac -h . $(CLASS_PATH)$*$(koncovka) clean : rm ProgramJNI.o ProgramJNI.dll
Teraz nás čaká vytvorenie a nastavenie pre build nášho nového Makefile. Jeho identifikáciu sme v Makefile definovali na "all". Tvorba targetu už bola ukázaná, takže opakujeme identický postup (čo znamená kliknutie v Project exploreru na Makefile a stlačení SHIFT + F9), a pridáme ďalšie (Add ...), kde definujeme meno (Target name) a buildovací príkaz (buildname). Potvrdíme OK.
V Target sa nám objaví ďalšia voľba "all". Na nej klikneme (zvýrazníme) a stlačíme tlačidlo "Build". Dole v konzole by sme mali vidieť vykonaný úspešný výpis. V Project exploreru možno vidieť vznik nových dvoch súborov a ProgramJNI.oa ProgramJNI.dll.
6 - Úprava Java triedy
Po úspešnom zbuildování * .dll knižnice sa vrátime do Javy. Prepneme perspektívu a zobrazíme si zdrojový kód spúšťací triedy v Jave. Najskôr vykonáme zavedenie knižnice a potom zavoláme natívne metódy.
public class ProgramJNI { static { try { System.loadLibrary("ProgramJNI"); System.out.println("Nactena knihovna ProgramJNI.dll"); } catch(UnsatisfiedLinkError e){ System.err.println("Nelze nacist knihovnu ProgramJNI.dll"); System.err.println(e.getMessage()); } } native void metodaTisk(); native int ziskejInt(); native int zvysIntDeset(int cislo); public static void main(String[] args) { System.out.println("Testovaci vypis JNI v Eclipse s makefile"); ProgramJNI program = new ProgramJNI(); program.metodaTisk(); System.out.println("Zde je vystup Java z nativni dll : "+program.ziskejInt()); System.out.println("Zde je vystup Java z nativni dll se " + "vstupem z Java : "+program.zvysIntDeset(123)); } }
7 - Volanie natívne metódy z Javy
Konečne prichádza finále, kedy si vyskúšame prvý program využívajúci JNI. Problém je v tom, že daná * .dll je uložená v adresári \ JNI \. Je nutné JVM informovať kde danú * .dll hľadať a to vykonáme v nastavení v konfigurátore spustení. Hore v menu zvolíme Run -> Run configurations ... a prevedieme nastavenie. V strome si nájdeme spúšťací triedu prepneme záložku Arguments -> VM argument a vložíme "-Djava.library.path = JNI". Potom klikneme na Apply a Run a uvidíme výsledok.
V budúcom dieli si konečne vytvoríme JNI projekt cez Eclipse IDE bez Makefile.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 532x (19.82 kB)