[Megoldva] JNA: natív könyvtár futtatási hiba

Fórumok

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

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$%#$#%^*^"

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$%#$#%^*^"

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.

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$%#$#%^*^"

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?

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.

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.

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