5. diel - JNI - Príklad v Eclipse bez Makefile as reťazcom
V minulom tutoriále o Java Native Interface sme si ukázali, ako vytvoriť JNI aplikáciu v IDE Eclipse CDI a použili sme k tomu Makefile.
Dnes si budeme pomáhať trochu aj príkazovým riadkom. Nie každý chce totiž v Eclipse používať Makefile. Opätovne je projekt takmer identický ako v predchádzajúcich dvoch dieloch. A aby sme to trochu okorenili, nebudeme využívať len primitívne dátové typy, ale pohráme si aj so STRING.
Osnova postupu
- Vytvoríme Java projekt vrátane spúšťací triedy (.java) a
skompilujeme pre Java8, 7, 6, ... (
.class
) - Vytvoríme hlavičkový súbor (* .h) a prekonvertuje do C / C ++ projektu
- Z header filu (hlavičkového súboru) vytvoríme source file (zdrojový súbor * .c)
- Nastavíme kompilátor a linker v Eclipse CDT IDE
- Vykonáme kompiláciu a linkovanie danej zdieľané knižnice (* .dll)
- Upravíme spúšťacie Java triedu, aby sme načítali natívne knižnicu a zavoláme natívne metódy z Javy
1 - Tvorba a kompilácie 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 kontrolný výstup. Je to identické z predchádzajúcej kapitolou.
public class ProgramString { native void metodaTest(); native String posliString(String str); public static void main (String [] args) { System.out.println("Testovací výpis z Javy"); } }
Čo danej metódy vlastne robia? Prvá metóda je jasná (pozri. Minulej kapitoly). Druhá metóda má návratový typ String, čo znamená, že natívny metóda nám prenesie hodnotu typu String z natívne časti programu do interpretované časti programu a zároveň je String aj parameter interpretované časti, ktorý sa prenesie do natívne. Iba vykonáme zmenu toho reťazca. Prakticky je to triviálne časť.
2 - Vytvorenie hlavičkového súboru a konverzie projektu
(Pre Java 9,8,7,6, ...) Pretože nám Eclipse neumožňuje v Project exploreru zobraziť * .class (skompilovanej Java triedy) a my potrebujeme vyrobiť cez "javah" hlavičkový súbor, tak budeme musieť spustiť navigator, ktorý nám zobrazí * .class súbory.
V navigátora klikneme na adresár \ bin \ a za pomocou klávesovej skratky CTRL + ALT + T sa nám v Eclipse zobrazí terminál. Jedná sa o obyčajný command prompt, dostupný v Eclipse od verzie 3.7. Vďaka nemu vygenerujeme za pomocou príkazu súbor * .h. Cez Popup menu vyvoláme refresh projektu a všimneme si vzniku súboru ProgramString.h (header file * .h) v adresári \ bin \. Tento súbor okamžite presunieme do adresára \ src \.
javah -jni ProgramString
Pre Java 10,11 [18.9], 12 [19.3], ...: V adresári \ src \ spustíme terminal a zadáme tento príkaz.
javac -h . ProgramString.java
Ako ďalšie 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, vyberieme C / C ++ -> zvolíme Convert to a C / C ++ Project. Ďalej nastavíme vlastnosti projektu. Zvolíme projekt a vyberieme C Projekt, zvolíme Shared Library (zdieľaná knižnica) project a typ kompilátora v našom prípade MinGW. Postup je takmer identický ako v predchádzajúcom článku.
Môžeme si všimnúť zmien Project exploreru v projekte. Projekt sa prekonvertovať. Samozrejme automaticky došlo k zmene perspektívy na C / C ++. Po konverzii projektu nám vzniknú nejaké error, ale zatiaľ si ich nevšímajte, čoskoro sa ich zbavíme.
3 - Vytvorenie zdrojového súboru C / C ++
Teraz si do adresára \ src \, kde je umiestnený zdrojový kód Java aplikácie a hlavičkový súbor, vytvoríme zdrojový kód pre knižnicu "ProgramString.c". 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, kam sa má vytvoriť, a do File name vyplníme názov.
Akonáhle vytvoríme zdrojový súbor * .ca vložíme tento kód, ktorý uložíme, tak by mali samy zmiznúť spomínané error. Doplníme hlavičky metód (funkcií) deklaráciami a vyplníme tela daných funkcií.
#include <jni.h> #include <stdio.h> #include "ProgramString.h" #include "string.h" JNIEXPORT void JNICALL Java_ProgramString_metodaTest(JNIEnv *env, jobject obj){ printf("Testovaci Vypis z Nativni casti JNI Programu"); } JNIEXPORT jstring JNICALL Java_ProgramString_posliString(JNIEnv *env, jobject obj, jstring str){ // zpracujeme vstupni retezec const char *retezec = (*env)->GetStringUTFChars(env, str, 0); printf("Zde je vlozeny retezec : %s\n", retezec); // POZOR pouze 256 znaku char veta [256]; // vlozeni retezce do pole charu strcpy(veta,"Ahoj jak se mas ?"); // slouceni retezcu v C-cku strcat(veta,retezec); jstring vystup = (*env)->NewStringUTF(env,veta); return vystup; }
Teraz si trochu preberieme čo sme vykonali. Prvý funkciu kvôli jednoduchosti preskočíme. Druhá funkcia už zaujímavejšie. C-čko samotnej nepodporuje String, takže je nutné ho za pomoci JNI metódy (funkcia) "GetStringUTFChars ()" previesť na pole char. Tu je zoznam všetkých JNI fukcií podporovaných v JNI API. Syntax C nebudem rozoberať. Ďalšie funkcie "NewStringUTF ()" vytvára String, ktorý potom presunieme do interpretované časti, je to návratová hodnota našej funkcie.
4 - Nastavenie kompilátora a linker
Teraz nás čaká najnudnejší, ale aj najdôležitejšia časť. Prevedieme nastavenie kompilátora / linker v Eclipse IDE. Klikneme (označíme) projekt a stlačíme ALT + ENTER. V strome si vyberieme C / C ++ Build -> Settings -> a tu v Configuration nastavíme All configurations.
Teraz vykonáme nastavenie kompilátora. V strome v záložke Tool Settings
vyberieme možnosť GCC C Compiler a do Command vložíme kompilátor pre 64bit
x86_64-w64-mingw32-gcc
. Skontrolujeme parametre v All options
-O3 -Wall -c -fmessage-length=0
. Pravdepodobne v defaultu budete
mať - O0, takže sa presuňte do Optimization a nastavte -O3. Inak ak by sme
nezastavili PATH k jni.ha jni_md.h, do PATH by sme tu kompilátora museli v
možnosti Includes (-I) danej paths nastaviť.
Ďalej vykonáme nastavenie linker. V strome sa prepneme na MinGW Linker a do
Command opäť vložíme kompilátor pre 64bit
x86_64-w64-mingw32-gcc
. Do možnosti Miscellaneous doplníme do
Linker flags tento reťazec -Wl,--add-stdcall-alias
a potom sa
späť prepneme do MinGW C Linker. Tu uvidíme upravený All options. (-Shared
... je tam defaultne a označuje tvorbu * .dll).
Zvolíme Apply a OK. Tým máme nastavený kompilátor aj builder.
5 - Kompilácia do * .dll
Čaká nás teda prevedenie tzv. "Buildu". Najskôr však vykonáme vyčistenie projektu. V menu zvolíme možnosť Project -> Clean ... -> označíme projekt a vypneme automatický build.
Potom klikneme na známe kladivko a build sa vykoná. Zdieľaná knižnica vznikne v adresári Debug, odkiaľ ju budeme v Java aplikácii načítať.
6 - Úprava Java triedy a volanie natívne metódy
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á načítanie knižnice a potom zavoláme natívne metódy.
public class ProgramString { static { try { System.loadLibrary("libProjektJNIEclipse"); System.out.println("Nactena knihovna libProjektJNIEclipse.dll"); } catch(UnsatisfiedLinkError e){ System.err.println("Nelze nacist knihovnu libProjektJNIEclipse.dll"); System.err.println(e.getMessage()); } } native void metodaTest(); native String posliString(String str); public static void main(String[] args) { System.out.println("Testovaci vypis z JAVY "); ProgramString program = new ProgramString(); program.metodaTest(); String s = "Isaac Asimov"; System.out.println("Zde je vystup : " +program.posliString(s)); } }
Pred samotným spustením Java triedy je v IDE nutné opäť projekt
vyčistiť. (Project -> Clean). Opätovne je nutné JVM informovať, kde
danú * .dll hľadať a toho docielime nastavením 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, kam vložíme -Djava.library.path=Debug
. Potom klikneme
na Apply a Run a uvidíme výsledok.
Využívať v kóde * .dll umiestnenou v adresári Debug nie je moc chytré.
Každým spúšťaním prebieha kompilácie a štruktúra adresára Debug sa
pokazí a prestane fungovať. Preto odporúčam vytvoriť nový adresár, napr.
"Dll", a do neho knižnicu nakopírovať. Pri spustení cez IDE je vhodné
upraviť VM argument -Djava.library.path=dll
. Všetko by malo
bežať v poriadku. Ak aplikáciu spúšťame z príkazového riadku cez IDE v
konzolu alebo priamo cez command prompt, nesmieme zabudnúť, že keď spustím
z adresára \ bin \, v tomto adresári sa adresár \ dll \ nenachádza a preto
je nutné povedať JVM nech hľadá adresár \ dll \ o úroveň vyššie, priamo
v roote projektu.
To je pre zatiaľ všetko, základná kostra riešenia bola ukázaná a jemné detaily rôznych dátových typov, objektov, pointer vs. referencie, vlákien, apod., to už bude na vás.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 10x (74 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java