Sziasztok!
(UBUNTU Linux 8.04, JDK1.6, gcc 4.2.4)
Szerettem volna megvalósítani egy megosztott könyvtár használatát Javaban a JNA segítségével. Odáig eljutottam nagy nehezen, hogy az *.so fájlt már betölti. Sajnos nem látja a benne lévő, általam használni kívánt, függvényt. Fontos tudni, hogy a lib-et is én hoztam létre. Csak azért mondom, mert lehet, hogy abban van a hiba.
Ez a Java pogram:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class DllLoader {
public interface myLibrary extends Library {
//static String myLib = this.libName();
String dirLinux = "/home/pj/xmp_02/DllLoader/native/";
String dirWin = "";
myLibrary INSTANCE = (myLibrary)
Native.loadLibrary((Platform.isWindows() ? dirWin+"xmp.dll" : dirLinux+"libxmp.so"),
myLibrary.class);
void printXX();
}
public static void main(String[] args) {
myLibrary.INSTANCE.printXX();
}
}
Ezt a hibaüzenetet kapom:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'printXX': /home/pj/xmp_02/DllLoader/native/libxmp.so: undefined symbol: printXX
A megosztott könyvtár forráskódja pedig így néz ki:
xmp.h:
#ifndef PJ__MY_XMP_H
#define PJ__MY_XMP_H
class LibClass {
public:
LibClass();
virtual ~LibClass();
void printSomething();
};
void printXX();
#endif
xmp.cpp:
#include "xmp.h"
#include < iostream >
LibClass::LibClass() {}
LibClass::~LibClass() {}
void LibClass::printSomething() {
std::cout << "Ez a program, csak kiir valamit.\n"
<< "Nincs mas szerepe, mint szemleltetni, "
<< "hogyan lehet egy dll fajlt meghivni a Java-ban.\n";
}
//-----------------------------------------------------------------
void printXX() {
LibClass lc;
lc.printSomething();
}
Szóval a kérdésem: Hol a hiba? A megosztott könyvtárban vagy a Java-ban? És hogyan orvosolható.
- 1526 megtekintés
Hozzászólások
extern C-vel deklarald a fuggvenyt a dll-ben. path.separatort meg ne hardkodold!
Szerk: JNA <-> JNI!
----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
- A hozzászóláshoz be kell jelentkezni
Valami ilyesmire gondolsz?
#ifdef __cplusplus
extern "C" {
#endif
... header code for foobar goes here ...
#ifdef __cplusplus
}
#endif
Bocs! Ezen mit értesz? "path.separatort meg ne hardkodold!"
- A hozzászóláshoz be kell jelentkezni
Igen, olyansmire.
Path.separator meg a konyvtarakat elvalaszto karakter, unix rendszereken altalaban /, windowson \. De most latom, hogy kulon valtozokban tarolod a ket eleresi utat, igy a jelenlegi kodban ez nem gond...
----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
- A hozzászóláshoz be kell jelentkezni
Igen!
Már működik is! Nagyon szépen köszönöm!
Megosztott könyvtáraknál be kell tenni ezt az extern "C" deklarációt? Enélkül miért nem megy?
- A hozzászóláshoz be kell jelentkezni
Csak akkor, ha: C++ forrasu a lib es nem C++ alol szeretned hasznalni, ugyanis a C++ fordito "obfuszkalja" a fuggvenyneveket, azaz valami idiota nevet ad neki. Ennek megvan a maga oka es logikaja, de ez itt most nem erdekes. Hiaba talalod ki, hogy az aktualis libbe epp ezt a fuggvenyt minek hivjak, mert az obfuszkalasi logika forditonkent es azon belul meg verzionkent is elterhet. Ezert kell az extern "C" C++ shared libeknel.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Ó, te jó ég!
Nahát! Kösz a felvilágosítás! :)
Tanulság: A téma nem a Java vagy a JNA problémája volt, hanem a C++ fordítóé.
- A hozzászóláshoz be kell jelentkezni
Szivesen!
Az utanam hozzaszolo altal emlitett "obfuszkalas"-t C++ name mangling vagy c++ name decoration-nak nevezik, ha guglin akarnal utananezni...
Amugy miert nem a prog.hu-n tetted fel a kerdest? Ciki lett volna..?
----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
- A hozzászóláshoz be kell jelentkezni
Ja, igen!
Természetesen neked is nagyon köszönöm!
(Megmondom őszintén, nem néztem a hozzászólók neveit.)
- A hozzászóláshoz be kell jelentkezni
Tudom, csak az o szamara ezen az ismereti szinten ez nem lett volna relevans info
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Gondoltam, hogy tudod! :^)
----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
- A hozzászóláshoz be kell jelentkezni
Ez igaz Windows esetén is?
Próbáltam Windows-ra is alkalmazni egyik ismerősömnél, de nem jött össze. Ugyanazt a "UnsatisfiedLinkError" hibát adja, mint korábban nálam Linuxon.
Windows esetén van még egyéb követelmény is, amit figyelembe kell venni?
- A hozzászóláshoz be kell jelentkezni
- Mivel forditottad?
- asszem kell valami dllexport cdecl is, de ebben nem vagyok egeszen biztos. Mindenesetre nez korul.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
MinGW (Dev-C++)
- A hozzászóláshoz be kell jelentkezni
Ezt írtam:
#ifndef MY_JNA_DLL_H_
#define MY_JNA_DLL_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#ifndef STDCALL
#define STDCALL __stdcall
#endif
#ifndef CDECL
#define CDECL __cdecl
#endif
#else
#define DLLEXPORT
#define STDCALL
#define CDECL
#endif
void DLLEXPORT STDCALL printXX();
class DLLIMPORT DllClass {
public:
DllClass();
virtual ~DllClass(void);
void printSomething();
private:
};
#ifdef __cplusplus
}
#endif
#endif /* _DLL_H_ */
Hol a hiba szerintetek?
- A hozzászóláshoz be kell jelentkezni
strings hasznalataval nezd meg, milyen nevu fuggvenyek keletkeznek a DLL-ben. A legnagyobb problema ott szokott lenni, hogy C esetere van szabvany nevezektan, C++ eseten nincs, ezert ahany fordito, annyifele fuggvenynev. Mi is szivtunk hasonoval, es par gcc meg linkerbeallitas csodakra kepes. kmARC volt nalunk a szakertoje ennek, ot kerdezd esetleg.
- A hozzászóláshoz be kell jelentkezni
A "strings", egy program neve?
- A hozzászóláshoz be kell jelentkezni
Igen.
- A hozzászóláshoz be kell jelentkezni
Ott, hogy az osztaly definicioja is belepottyant az extern "C" hatokorebe, az pedig az almoskonyvek szerint legalabbis nem sok jot jelent. A lezarasat vidd a void fole, es a class-sal valo visszatereshez csinalj egy factory fuggvenyt. Pl:
class A {
public:
A() : sum(0), nn(0) {}
void add(const int n) { sum += n; nn++; }
int getAvg() { return sum / nn; }
private:
int sum, nn;
};
#ifdef __cplusplus
extern "C" {
#endif
A *getA() {
return new A();
}
#ifdef __cplusplus
} // extern "C"
#endif
Igy csak a getA -nak lesz C stilusu neve, az osztalyokkal ez amugy sem biztos, hogy megoldhato dolog. Mindenesetre egy uj A peldanyt ilyen factory fuggvenyen keresztul kaphatsz.
PS: En is tudom, hogy ez a kod borzaszto randa...
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Hát, egyelőre köszönöm! Kipróbáljuk. Ha nem működik, még jelentkezem.
- A hozzászóláshoz be kell jelentkezni
Sziasztok!
Sikerült megoldanom. Fontos tudni, hogy csak akkor lett jó, amikor a __stdcall-t betettem a programba. Ráadásul mindkét fájba, azaz a fejléc állományba (*.h) és az implementációs állományba (*.cpp) is be kellett illesztenem a függvény elé.
A végleges program így néz ki:
xmp.h
#ifndef MY_JNA_XMP_H_
#define MY_JNA_XMP_H_
class DllClass {
public:
DllClass();
virtual ~DllClass(void);
void printSomething();
};
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#ifndef STDCALL
#define STDCALL __stdcall
#endif
#ifndef CDECL
#define CDECL __cdecl
#endif
#else
#define DLLEXPORT
#define STDCALL
#define CDECL
#endif
DLLEXPORT STDCALL void printXX();
#ifdef __cplusplus
}
#endif
#endif
------------------------------------------------------
xmp.cpp
#include "xmp.h"
#include <iostream>
#include <windows.h>
DllClass::DllClass() {}
DllClass::~DllClass() {}
void DllClass::printSomething() {
std::cout << "Ez a program, csak kiir valamit.\n"
<< "Nincs mas szerepe, mint szemleltetni, "
<< "hogyan lehet egy dll fajlt meghivni a Java-ban.\n";
}
DLLEXPORT STDCALL void printXX() {
DllClass dc;
dc.printSomething();
}
- A hozzászóláshoz be kell jelentkezni