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

6. diel - JNI - Príklad v Eclipse s C ++

V minulom tutoriále o JNI sme sa naučili natívne pracovať s textovými reťazcami. Dnes vytvoríme JNI aplikácii za pomocou IDE Eclipse s balíčkom CDT. Jediný rozdiel bude, že vzniknutú knižnicu .dll vytvoríme za pomoci C ++. Bude využitá syntaxe C ++ a hlavne C ++ kompilátor a linker. Postup bude vykonaný bez Makefile (viď. Predchádzajúca kapitola), takže si budeme pomáhať trochu aj príkazovým riadkom. Ďalej je nutné upozorniť, že JNI je vyvinuté hlavne pre C. Preto neexistujú priame väzby v programovej časti medzi JNI a C ++. Vždy je nutné využiť prostredníka - Cčko. Možno vám tento diel pripadne zbytočný, prakticky sa dá zvládnuť za pomoci analógie (mierne zmeny v Eclipse a MinGW) a znalostí C / C ++. Napriek tomu si myslím, že je vhodné si toto riešenie predviesť.

Osnova postupu

  1. Vytvoríme Java projekt vrátane spúšťací triedy (.java) a skompilujeme (.class)
  2. Vytvoríme hlavičkový súbor (.h) a prekonvertuje do C ++ projektu
  3. Z header filu (.h) (hlavičkového súboru) vytvoríme source file (zdrojový súbor .cpp)
  4. Nastavíme kompilátor a linker pre C ++ v Eclipse CDT IDE
  5. Vykonáme kompiláciu a linkovanie danej zdieľané knižnice (.dll)
  6. 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 ProgramJNICpp {
    native void vlozInt(int cislo);
    native int ziskejInt();
    native void posliString(String s);
    native String upravString(String s);
    public static void main(String[] args) {
        System.out.println("Start Programu");
    }
}
Nastavenie Java projektu - JNI - Java Native Interface

Teraz si trochu preberme čo sme vlastne napísali:

Čo danej metódy vlastne robia? Prvá metóda posiela int do natívnej časti. Druhá z natívne časti integer získava. Tretia metóda posiela String do natívne časti a štvrtá metóda posiela String do natívne časti a zároveň ho získava. Prakticky v tejto metóde vykonáme úpravu vstupného STRING. V zásade nič zložitého a jedná sa metódy a ich kombinácie z predchádzajúcich kapitol.

2 - Tvorba hlavičkového súboru a zmena projektu

Ako ďalší krok vykonáme vytvorenie hlavičkového súboru (header file .h). V prípade Java9,8,7 v navigátora si označíme adresár \ bin \ a za pomocou Terminálu vyrobíme hlavičkový súbor (.h). Tento súbor okamžite presunieme do adresára \ src \. V prípade Java10,11,12, .. vyrobíme header file v adresári \ src \. Ako ďalší krok vykonáme zmenu projektu na C / C ++. 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 a nastavíme vlastnosti projektu. Ďalej zvolíme projekt, 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.

hlavičkový súbor - JNI - Java Native Interface

Po konverzii projektu vám vzniknú nejaké opäť error. Zas sa ich čoskoro zbavíme.

3 - Vytvorenie zdrojového súboru (.cpp)

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 "ProgramJNICpp­.cpp". Do vzniknutého zdrojového súboru umiestnime tento zdrojový kód. Pretože využívame C ++, je nutné samozrejme používať / naincludovat iné knižnice. K plnému pochopeniu je nutná znalosť C ++. Rozoberať syntax C ++ nie je predmetom tohto článku. Avšak kto disponuje aspoň primitívnymi základy, tak by daný kód mal pochopiť bez problému.

#include <jni.h>
#include <iostream>
#include <string>
#include <cstring>
#include "ProgramJNICpp.h"

using namespace std;

JNIEXPORT void JNICALL Java_ProgramJNICpp_vlozInt(JNIEnv *env , jobject obj, jint cislo){
    cout << "Vypis cisla z Nativni casti : " << cislo << "\n";
}

JNIEXPORT jint JNICALL Java_ProgramJNICpp_ziskejInt(JNIEnv *env, jobject obj){
    jint mojeCislo=123;
    return mojeCislo;
}

JNIEXPORT void JNICALL Java_ProgramJNICpp_posliString(JNIEnv *env, jobject obj, jstring str){
    //  presuneme jstring na Cckovy String
    const char* s = env->GetStringUTFChars(str,NULL);
    cout << "Vypis Stringu z Nativni casti : " << s << "\n";
}

JNIEXPORT jstring JNICALL Java_ProgramJNICpp_upravString(JNIEnv *env, jobject obj, jstring str){
    //  presuneme jstring na Cckovy String
    const char* s = env->GetStringUTFChars(str,NULL);
    // presuneme Cckovy string na C++ string
    string txtInterpret(s,strlen(s));
    string txtNativ = " - Nativni String";
    txtInterpret += txtNativ;
    cout << "Vypis Stringu z Nativni casti behem upravy : " << txtInterpret << "\n";
    //  do jstringu je nutno prevest C++ string na C string
    jstring vystup = env->NewStringUTF(txtInterpret.c_str());
    return vystup;
}

)

Opäť si preberieme čo sme to urobili. Prvá funkcia využíva iba výpis integer hodnoty, ktorú do natívne časti pošleme z interpretované časti. Druhá funkcia vracia z natívne časti iba celočíselnú hodnotu, ktorú sme si v natívnej časti definovali. Tretia funkcia je už zaujímavá. JNI má problém v tom, že priamo nepodporuje C ++ syntax. Takže je nutné vždy pri zložitejších dátových typov vykonať prevod najskôr na Cčko a potom až na C ++. Rovnaký problém je teda logicky aj vo funkcii číslo 4. Pretože táto kapitola sa týka C ++, tak využívam funkcie C ++ a teda je nutné je samozrejme prevádzať cez sprostredkujúcu C syntax. Len pripomínam, že tu sú JNI funkcie ktoré sú podporované v API.

zdrojáky CPP - JNI - Java Native Interface

4 - Nastavenie kompilácie a linkovanie v Eclipse

Opätovne vykonáme 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 záložke Tool Settings -> a v strome si vyberieme možnosť GCC C ++ Compiler. Do Command vložíme kompilátor pre 64bit x86_64-w64-mingw32-g++. Skontrolujeme parametre v All options -O3 -Wall -c -fmessage-length=0. Áno, "g ++" označuje kompilátor / linker pre C ++ a "gcc", ktorý sme použil v predchádzajúcom diele, je kompilátor / linker pre Cčko.

Nastavenie kompilátora pre C ++ - JNI - Java Native Interface

Tu 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-g++. 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.

Nastavenie linker C ++ - JNI - Java Native Interface

5 - Kompilácia a linkovanie zdieľané knižnice (Build)

Teraz nás čaká prevedení tvz. "Buildu". Najskôr však urobme vyčistenie projektu. Toto docielime možnosťou Project -> Clean v menu. 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 nebudeme v Java aplikácii načítať.

Build dll - JNI - Java Native Interface

6 - Upravíme Java triedu a otestujeme funkčnosť projektu

Po úspešnom zbuildování * .dll knižnice sa vrátime do Javy. Danú (.dll) prekopíruje do adresára \ src \ a premenujeme na napr. "Knihovna.dll". Prepneme perspektívu a zobrazíme si zdrojový kód spúšťací triedy v Jave. Najskôr vykoná načítanie knižnice (v adresári \ src) a potom zavoláme natívne metódy.

public class ProgramJNICpp {
    static {
        try {
            System.loadLibrary("src/knihovna");
            System.out.println("Nactena knihovna knihovna.dll");
        }
        catch(UnsatisfiedLinkError e){
            System.err.println("Nelze nacist knihovnu knihovna.dll");
            System.err.println(e.getMessage());
        }
    }
    native void vlozInt(int cislo);
    native int ziskejInt();
    native void posliString(String s);
    native String upravString(String s);
    public static void main(String[] args) {
        System.out.println("Start Programu");
        ProgramJNICpp program = new ProgramJNICpp();
        program.vlozInt(123123);
        System.out.println("Vystup int : "+program.ziskejInt());
        program.posliString("Muj testovaci String");
        System.out.println("Vystup String : "+program.upravString("Retezec Interpret"));
    }
}

Pri spustení v tomto prípade nie je nutné nastavovať VM argument -Djava.library.path, pretože sme .dll vložili do adresára \ src \ a pri načítaní knižnice sme daný adresár špecifikovali. Java kód knižnicu bez problémov nájde. Čo sa však nedá povedať o spustenie z command prompt, to už nechám na vás. Rôzne spôsoby načítanie (.dll) pre rôzne varianty boli predvedené v predchádzajúcich kapitolách.

Test spustenie JNI aplikácie s C ++ - JNI - Java Native Interface

Rozdiel medzi C a C ++ syntaxou prí volanie JNI metód cez JNIEnv * env je:

/* C syntaxe */
jsize delkaPole = (*env)->GetArrayLength(env,array);
/* C++ syntaxe */
jsize delkaPole = env->GetArrayLength(array);

Nabudúce nás čakajú primitívne dátové typy.


 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 439x (229.42 kB)

 

Predchádzajúci článok
JNI - Príklad v Eclipse bez Makefile as reťazcom
Všetky články v sekcii
JNI - Java Native Interface
Preskočiť článok
(neodporúčame)
JNI - Primitívne dátové typy
Č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