IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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.

  1. Vytvoríme Java projekt vrátane spúšťací triedy (.java) a skompilujeme (.class)
  2. Prekonvertuje Java project do C / C ++ projektu
  3. Vytvoríme konfiguračný súbor buildu Makefile a v projekte vytvoríme hlavičkový súbor (* .h)
  4. Z header filu (hlavičkového súboru) vytvoríme source file (zdrojový súbor * .c)
  5. Daný zdrojový súbor skompilujeme a nalinkuje, vznikne * .dll súbor
  6. Upravíme spúšťacie Java triedu, aby sme načítali natívne knižnicu
  7. 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ť.

Predvolené nastavenie Java projektu - JNI - Java Native Interface

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.

Konverzia projektu - JNI - Java Native Interface

Objaví sa dialógové okno New a vyberieme C / C ++. Zvolíme Convert to a C / C ++ Project.

výber konverzie - JNI - Java Native Interface

Nastavíme vlastnosti projektu. Zvolíme projekt, vyberieme C Projekt, zvolíme Makefile project a typ kompilátora v našom prípade MinGW.

nastavenie konverzie - JNI - Java Native Interface

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.

skonvertovaný projekt - JNI - Java Native Interface

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.

vytvorenie adresára - JNI - Java Native Interface

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".

Vytvorenie Makefile súboru - JNI - Java Native Interface

(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)
Makefile - JNI - Java Native Interface

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.

vytvorenie target - JNI - Java Native Interface

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.

nastavenie BUILD - JNI - Java Native Interface

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:

Build projektu - JNI - Java Native Interface
header File - JNI - Java Native Interface

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;
}


zdrojový súbor - JNI - Java Native Interface

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
nový Makefile - JNI - Java Native Interface

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.

VytvoreniTargetu - JNI - Java Native Interface

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.

vykonaný Build - JNI - Java Native Interface

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));
    }
}


Zdrojový kód Java - JNI - Java Native Interface

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.

Nastavenie a spustenie JNI aplikácie - JNI - Java Native Interface
Vystúp Java Native Interface aplikácie v Eclipse - JNI - Java Native Interface

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 podmienkami

Stiahnuté 532x (19.82 kB)

 

Predchádzajúci článok
JNI - Prvý príklad Java Native Interface bez IDE
Všetky články v sekcii
JNI - Java Native Interface
Preskočiť článok
(neodporúčame)
JNI - Príklad v Eclipse bez Makefile as reťazcom
Článok pre vás napísal Robert Michalovič
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Programuji převážně v Javě SE,EE a trochu nativním C a CUDA. více viz.https://cz.linkedin.com/in/robert-michalovic
Aktivity