5. díl - JNI - Příklad v Eclipse bez makefile a s řetězcem

Java Pro pokročilé JNI JNI - Příklad v Eclipse bez makefile a s řetězcem

V minulém tutoriálu o Java Native Interface jsme si ukázali, jak vytvořit JNI aplikaci v IDE Eclipse CDI a použili jsme k tomu makefile.

Dnes si budeme pomáhat trochu i příkazovým řádkem. Ne každý chce totiž v Eclipse používat makefile. Opětovně je projekt téměř identický jako v předchozích dvou dílech. A abychom to trochu okořenili, nebudeme využívat jen primitivní datové typy, ale pohrajeme si i se Stringem.

Osnova postupu

  1. Vytvoříme Java projekt včetně spouštěcí třídy (.java) a zkompilujeme (.class)
  2. Vytvoříme hlavičkový soubor (*.h) a překonvertujeme do C/C++ projektu
  3. Z header filu (hlavičkového souboru) vytvoříme source file (zdrojový soubor *.c)
  4. Nastavíme kompilátor a linker v Eclipse CDT IDE
  5. Provedeme kompilaci a linkování dané sdílené knihovny (*.dll)
  6. Upravíme spouštěcí Java třídu, abychom načetli nativní knihovnu a zavoláme nativní metody z Javy

1 - Tvorba a kompilace Java projektu

Jako první krok samozřejmě zkontrolujeme perspektivu, musí být nastavená Java. Dále vytvoříme Java projekt, který si nějak pojmenujeme. Vytvoříme spouštěcí třídu bez balíčku a doplníme tělo spouštěcí metody + navrhneme nativní metody. Program spustíme a dole v konzole si zkontrolujeme kontrolní výstup. Je to identické z předchozí 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");
        }
}

Co dané metody vlastně dělají? První metoda je jasná (viz. minulé kapitoly). Druhá metoda má návratový typ String, což znamená, že nativní metoda nám přenese hodnotu typu String z nativní části programu do interpretované části programu a zároveň je String i parametr interpretované části, který se přenese do nativní. Pouze provedeme změnu toho řetězce. Prakticky je to triviální část.

Java třída s nativními metodami

2 - Vytvoření hlavičkového souboru a konverze projektu

Jako další krok vytvoříme hlavičkový soubor (header file *.h). Protože nám Eclipse neumožňuje v Project exploreru zobrazit *.class (zkompilované Java třídy) a my potřebujeme vyrobit přes "javah" hlavičkový soubor, tak budeme muset spustit navigator, který nám zobrazí *.class soubory.

Nastavení navigátoru

V navigátoru klikneme na adresář \bin\ a za pomocí klávesové zkratky CTRL+ALT+T se nám v Eclipse zobrazí terminál. Jedná se o obyčejný command prompt, dostupný v Eclipse od verze 3.7. Automaticky se nastaví cesta do adresáře \src\ v řešeném projektu. Díky němu vygenerujeme za pomocí příkazu

javah -jni ProgramString

soubor *.h. Přes Popup menu vyvoláme refresh projektu a všimneme si vzniku souboru ProgramString.h v adresáři \bin\. Tento soubor okamžitě přesuneme do adresáře \src\.

Vytvoření hlavičkového souboru

Jako další provedeme konverzi z Java Projektu na C/C++ projekt. K tomu samozřejmě nestačí jen změnit perspektivu. Konverzi provedeme dle obrázku. Označíme projekt, který chceme zkonvertovat, a vyvoláme Popup okno -> new -> other. Objeví se dialogové okno New, vybereme C/C++ -> zvolíme Convert to a C/C++ Project. Dále nastavíme vlastnosti projektu. Zvolíme projekt a vybereme C Projekt, zvolíme Shared Library (sdílená knihovna) project a typ kompilátoru v našem případě MinGW. Postup je téměř identický jako v předchozím článku.

Změna projektu

Můžeme si všimnout změn Project exploreru v projektu. Projekt se překonvertovat. Samozřejmě automaticky došlo ke změně perspektivy na C/C++. Po konverzi projektu nám vzniknou nějaké errory, ale zatím si jich nevšímejte, brzy se jich zbavíme.

3 - Vytvoření zdrojového souboru C/C++

Nyní si do adresáře \src\, kde je umístěn zdrojový kód Java aplikace a hlavičkový soubor, vytvoříme zdrojový kód pro knihovnu "ProgramString.c". Označíme daný adresář a opět vyvoláme Popup okno. Vybereme cestu New -> File -> a objeví se nám opět dialogové okno. Zvolíme adresář, kam se má vytvořit, a do File name vyplníme název.

Vytvoření zdrojového souboru C/C++

Jakmile vytvoříme zdrojový soubor *.c a vložíme tento kód, který uložíme, tak by měly samy zmizet zmíněné errory. Doplníme hlavičky metod (funkcí) deklaracemi a vyplníme těla daných funkcí.

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

Nyní si trochu probereme co jsme provedli. První funkci kvůli jednoduchosti přeskočíme. Druhá funkce již zajímavější. C-čko samotné nepodporuje String, takže je nutné jej za pomoci JNI metody (funkce) "GetStringUTFChar­s()" převést na pole charů. Zde je seznam všech JNI fukcí podporovaných v JNI API. Syntaxi C nebudu rozebírat. Další funkce "NewStringUTF()" vytváří String, který poté přesuneme do interpretované části, je to návratová hodnota naší funkce.

Vypsání zdrojového kódu

4 - Nastavení kompilátoru a linkeru

Nyní nás čeká nejnudnější, ale také nejdůležitější část. Provedeme nastavení kompilátoru/linkeru v Eclipse IDE. Klikneme (označíme) projekt a stiskneme ALT+ENTER. Ve stromu si vybereme C/C++ Build -> Settings -> a zde v Configuration nastavíme All configurations.

Nastavení projektu

Nyní provedeme nastavení kompilátoru. Ve stromu v záložce Tool Settings vybereme možnost GCC C Compiler a do Commandu vložíme kompilátor pro 64bit x86_64-w64-mingw32-gcc. Zkontrolujeme parametry v All options -O3 -Wall -c -fmessage-length=0. Pravděpodobně v defaultu budete mít – O0, takže se přesuňte do Optimization a nastavte -O3. Jinak pokud bychom nestavili PATH k jni.h a jni_md.h, do PATH bychom zde kompilátoru museli v možnosti Includes (-I) dané paths nastavit.

Nastavení kompilace

Dále provedeme nastavení linkeru. Ve stromu se přepneme na MinGW Linker a do Commandu opět vložíme kompilátor pro 64bit x86_64-w64-mingw32-gcc. Do možnosti Miscellaneous doplníme do Linker flags tento řetězec -Wl,--add-stdcall-alias a poté se zpět přepneme do MinGW C Linker. Zde uvidíme upravený All options. (-shared ... je tam defaultně a označuje tvorbu *.dll).

Nastavení linkeru

Zvolíme Apply a OK. Tím máme nastaven kompilátor i builder.

5 - Kompilace do *.dll

Čeká nás tedy provedení tzv. "buildu". Nejdříve ovšem provedeme vyčištění projektu. V menu zvolíme možnost Project -> Clean ... -> označíme projekt a vypneme automatický build.

Poté klikneme na známé kladívko a build se provede. Sdílená knihovna vznikne v adresáři Debug, odkud ji budeme v Java aplikaci načítat.

Provedení buildu

6 - Úprava Java třídy a volání nativní metody

Po úspěšném zbuildování *.dll knihovny se vrátíme do Javy. Přepneme perspektivu a zobrazíme si zdrojový kód spouštěcí třídy v Javě. Nejdříve provede načtení knihovny a poté zavoláme nativní metody.

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


Nastavení Java třídy pro volání native metod

Před samotným spuštěním Java třídy je v IDE nutno opět projekt vyčistit. (Project -> Clean). Opětovně je nutno JVM informovat, kde danou *.dll hledat a toho docílíme nastavením v konfigurátoru spuštění. Nahoře v menu zvolíme Run -> Run configurations ... a provedeme nastavení. Ve stromu si najdeme spouštěcí třídu přepneme záložku Arguments -> VM argument, kam vložíme -Djava.library.path=Debug. Poté klikneme na Apply a Run a uvidíme výsledek.

Spuštění JNI projektu

Využívat v kódu *.dll umístěnou v adresáři Debug není moc chytré. Každým spouštěním probíhá kompilace a struktura adresáře Debug se poškodí a přestane fungovat. Proto doporučuji vytvořit nový adresář, např. "dll", a do něj knihovnu nakopírovat. Při spuštění přes IDE je vhodné upravit VM argument -Djava.library.path=dll. Vše by mělo běžet v pořádku. Pokud aplikaci spouštíme z příkazového řádku přes IDE v konzoli nebo přímo přes command prompt, nesmíme zapomenout, že když spustím z adresáře \bin\, v tomto adresáři se adresář \dll\ nenachází a proto je nutné říci JVM ať hledá adresář \dll\ o úroveň výše, přímo v rootu projektu.

Testovací výpis

To je pro zatím vše, základní kostra řešení byla ukázána a jemné detaily různých datových typů, objektů, pointer vs. reference, vláken, apod., to již bude na vás.


 

Stáhnout

Staženo 3x (74 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

  Aktivity (3)

Článek pro vás napsal Robert Michalovič
Avatar
viz. linkedin

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 


Miniatura
Všechny články v sekci
JNI - Java Native Interface
Miniatura
Následující článek
JNI - Příklad v Eclipse s C++

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!