
C++ dlopen mini-HOGYANAaron Isotton

   aaron@isotton.com

   2003.08.12
   Verzitrtnet
   Verzi: 1.03 2003.08.12 tdolgozta: AI
   Referencia hozzadsa a GLib dinamikus modul betltjrl. Ksznet
   rte G. V. Sriraam-nak.
   Verzi: 1.02 2002.12.08 tdolgozta: AI
   GYIK hozzadsa. Kisebb vltoztatsok.
   Verzi: 1.01 2002.06.30 tdolgozta: AI
   Frisstett magyarzat a virtulis dekonstuktorokrl. Kisebb
   vltoztatsok.
   Verzi: 1.00 2002.06.19 tdolgozta: AI
   A "Szerzi jog s licenc" fejezet az elejre kerlt. "A dokumentumban
   hasznlt kifejezsek" fejezet hozzadsa. Kisebb vltoztatsok.
   Verzi: 0.97 2002.06.19 tdolgozta: JYG
   Egy kis sztr, valamint mondat-szint vltoztatsok.
   Verzi: 0.96 2002.06.12 tdolgozta: AI
   Irodalomjegyzk hozzadsa. Az extern fggvnyek s vltozk
   lersnak javtsa.
   Verzi: 0.95 2002.06.11 tdolgozta: AI
   Kisebb javtsok.

   C++ fggvnyek s osztlyok betltse a dlopen API segtsgvel.
     _________________________________________________________________

   Tartalomjegyzk
   1. [1]Bevezet

        1.1. [2]Szerzi jog s licenc
        1.2. [3]A felelssg teljes elhrtsa
        1.3. [4]Kzremkdk
        1.4. [5]Visszajelzs
        1.5. [6]A dokumentumban hasznlt kifejezsek
        1.6. [7]Magyar fordts

   2. [8]A problma

        2.1. [9]"Nv sztszedse"
        2.2. [10]Osztlyok

   3. [11]A megolds

        3.1. [12]extern "C"
        3.2. [13]Fggvnyek betltse
        3.3. [14]Osztlyok betltse

   4. [15]Gyakran Ismtelt Krdsek
   5. [16]Tovbbi informci
   [17]Irodalomjegyzk

1. Bevezet

UNIX C++ programozkban felmerl gyakori krds, hogyan tltsenek be
dinamikusan C++ fggvnyeket s osztlyokat a dlopen hasznlatval.

Tny, hogy nem minden esetben egyszer ez, s nmi magyarzatot ignyel. Ez
van lerva ebben a mini-HOGYANban.

Egy tlagos C s C++ programozsi nyelv ismeret valamint a dlopen API
ismerete szksges ahhoz, hogy megrthesd ezt a dokumentumot.

Ez a HOGYAN elsdleges a
[18]http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ webhelyen tallhat
meg.
     _________________________________________________________________

1.1. Szerzi jog s licenc

This document, C++ dlopen mini HOWTO, is copyrighted (c) 2002 by Aaron
Isotton. A dokumentum a Free Software Foundation ltal kiadott GNU Free
Documentation License 1.1-es vagy jabb verzijban foglalt felttelek
keretein bell msolhat, terjeszthet s/vagy mdosthat; invarins
fejezet, els s hts bortlapszveg nincsen.
     _________________________________________________________________

1.2. A felelssg teljes elhrtsa

A dokumentum tartalmrt nincs felelssgvllals. Az elgondolsokat,
pldkat s informcikat a sajt felelssgedre hasznld. Elfordulhatnak
hibk s pontatlansgok, amelyek a rendszered srlst okozhatjk. Minden
vatossg ellenre brmily hihetetlen, a szerz(k) semmilyen felelssget
nem vllal(nak).

Minden szerzi jog fenntartva az eredeti tulajdonosnak, amennyiben msknt
nincs jellve. A dokumentumban hasznlt szakkifejezsek semmilyen prhuzamot
nem kpviselnek vdjegyekre, szervz mrkkra vonatkozlag. Egyedi alkotsok
vagy vdjegyek nevestse nem hozzjrulsok.
     _________________________________________________________________

1.3. Kzremkdk

rmmel mondok ksznetet az albbi szemlyeknek (abc sorrendben):

     * Joy Y Goodreau <[19]joyg (at) us.ibm.com> a szerkesztsrt.
     * D. Stimitis <[20]stimitis (at) idcomm.com> rmutatott nhny
       krdsre a formzssal s a nv sztszedssel kapcsolatban valamit
       az extern "C"-vel kapcsolatban.
     _________________________________________________________________

1.4. Visszajelzs

Visszajelzst szvesen fogadok. A megjegyzseidet, kritikdat s a
hozzjrulsaidat a <[21]aaron@isotton.com> cmre kldheted.
     _________________________________________________________________

1.5. A dokumentumban hasznlt kifejezsek

   dlopen API
          A dlclose, dlerror, dlopen s dlsym fggvnyek, amik lersa a
          dlopen(3) kziknyv oldalon tallhat.

          Megjegyezzk, hogy mi a "dlopen" kifejezst a dlopen fggvnyre
          magra, s a "dlopen API" kifejezst az egsz API-ra
          hasznljuk.
     _________________________________________________________________

1.6. Magyar fordts

A magyar fordtst [22]Szalai Ferenc ksztette (2004.04.17). A lektorlst
[23]Daczi Lszl vgezte el (2004.05.04). Utoljra javtva 2004.05.05.-n
(r2). A dokumentum legfrissebb vltozata megtallhat a [24]Magyar Linux
Dokumentcis Projekt honlapjn.
     _________________________________________________________________

2. A problma

Nha futsidben kellene betlteni programknyvtrakat (s hasznlni a
fggvnyeiket). Ez leginkbb akkor szksges, ha valamilyen plug-in vagy
modul architektrj programot rsz.

A C nyelvben a program knyvtrak betltse igen egyszer (dlopen, dlsym s
dlclose meghvsa elegend). C++-al ez egy kicsit bonyolultabb. A C++
program knyvtrak betltsnek nehzsget rszint a [25]"nevek
sztszedse", rszben pedig az a tny okozza, hogy a dlopen API C-ben lett
rva, gy nem teszi lehetv osztlyok egyszer betltst.

Mieltt bemutatnnk a programknyvtrak betltst, C++-ban megvizsgljuk a
"nv sztszedsi" problmt egy kicsit alaposabban. Azt ajnlom akkor is
olvasd el ezt a rszt, ha nem rdekel, mert segt megrteni mi is a problma
s mi a megoldsa.
     _________________________________________________________________

2.1. "Nv sztszedse"

Minden C++ programban (vagy programknyvtrban vagy trgykd llomnyban)
minden nem statikus fggvny a binris llomnyban szimblumokkal van
reprezentlva. Ezek a szimblumok specilis karaktersorozatok, amik
egyrtelmen azonostjk a fggvnyt a programban, programknyvtrban vagy
trgykd llomnyban.

C-ben a szimblum nevek megegyeznek a fggvnyek neveivel: az strcpy
fggvny szimbluma strcpy s gy tovbb. Ez azrt lehetsges, mert C-ben
kt nem statikus fggvnynek nem lehet azonos a neve.

Mivel a C++ engedlyezi az tdefinilst (overloading - klnbz
fggvnyek azonos nvvel, de klnbz argumentumokkal), valamint szmos j
tulajdonsga van, ami a C-nek nincs -- mint osztlyok, tagfggvnyek,
kivtel kezels -- ezrt nem lehetsges a fggvnyek nevt egyszeren
szimblumnvnek hasznlni. A C++ ezt az problmt az gynevezett "nv
sztszedssel" (mangling) oldja meg. Ez gy mkdik, hogy a a fggvnyek s
egyb szksges informcik (mint az argumentumok szma s mrete) alapjn
ltrehoz egy csak a fordt szmra rtelmes karaktersorozatot, amit az
szimblum nvnek tud hasznlni. A foo fggvny ilyen mdon ellltott neve
gy nzhet ki pldul: foo@4%6^. Vagy nem is felttlen kell tartalmaznia a
"fo szt magt.

Az egyik problma ezzel az eljrssal az, hogy a C++ standard (jelenleg
[ISO14882]) nem definilja ennek a menett. gy minden fordt a sajt
mdszert hasznlja. Nhny fordt meg is vltoztatja az algoritmust
verzirl verzira (klnsen a g++ 2.x s 3.x kztt). Ezrt ha ki is
talltad, hogy a te fordtd hogyan is mkdik e tekintetben (s gy be
fogod tudni tlteni a fggvnyeidet a dlsym segtsgvel) ez valsznleg
csak a te fordtddal fog mkdni s hasznlhatatlan lesz annak kvetkez
verzijval.
     _________________________________________________________________

2.2. Osztlyok

A msik problma a dlopen API-val, az, hogy csak fggvnyek betltst
tmogatja. ltalban azonban egy C++ programknyvtrban egy osztlyt
publiklsz, amit a programodban hasznlni szeretnl. Ezen osztly
hasznlathoz egy pldnyt kell belle ksztened, de ez nem is olyan
knny.
     _________________________________________________________________

3. A megolds

3.1. extern "C"

A C++-nak van egy specilis kulcsszava arra, hogy fggvnyeket C ktssel
definiljuk. Ez az extern "C". Az a fggvny ami extern "C"-knt lett
definilva annak fggvnyneve szimblumknt hasznlhat akrcsak egy C
fggvnynek. Ezrt csak nem-tagfggvnyek deklarlhatk extern "C"
segtsgvel, s ezeket nem lehet tdefinilni.

Habr van nhny megkts az extern "C" fggvnyekre, mgis igen hasznosak,
mivel dinamikusan betlthetek a dlopen segtsgvel akrcsak a C
fggvnyek.

Ez nem jelenti azt, hogy az extern "C"-vel definilt fggvnyek nem
tartalmazhatnak C++ kdot. Az ilyen fggvnyek teljes rtk C++
fggvnyek, kihasznlhatjk a C++ lehetsgeit s brmilyen tpus
argumentummal rendelkezhetnek.
     _________________________________________________________________

3.2. Fggvnyek betltse

C++ a fggvnyek gy tlthetek be mint C-ben; a dlsym segtsgvel. A
betlteni kvnt fggvnyeket extern "C"-vel kell jellnd, hogy a C-szer
szimblum nvkpzst kiknyszertsd.

   Plda 1. Egy fggvny betltse

   main.cpp:
#include <iostream>
#include <dlfcn.h>


int main() {
    using std::cout;
    using std::cerr;

    cout << "C++ dlopen demo\n\n";

    // open the library
    cout << "Opening hello.so...\n";
    void* handle = dlopen("./hello.s, RTLD_LAZY);

    if (!handle) {
        cerr << "Cannot open library: " << dlerror() << '\n';
        return 1;
    }

    // load the symbol
    cout << "Loading symbol hello...\n";
    typedef void (*hello_t)();
    hello_t hello = (hello_t) dlsym(handle, "hell);
    if (!hello) {
        cerr << "Cannot load symbol 'hello': " << dlerror() <<
            '\n';
        dlclose(handle);
        return 1;
    }

    // use it to do the calculation
    cout << "Calling hello...\n";
    hello();

    // close the library
    cout << "Closing library...\n";
    dlclose(handle);
}

   hello.cpp:
#include <iostream>

extern "C" void hello() {
    std::cout << "hell << '\n';
}

   A hello fggvny a hello.cpp llomnyban van definilva, mint extern
   "C". A main.cpp-ben tltdik be a dlsym hvssal. A fggvnyt extern
   "C"-vel kell megjellni, mert klnben nem tudjuk biztosan a hozz
   tartoz szimblumnevet.

   Figyelem

   Kt tpusa ltezik az extern "C" deklarcinak: extern "C" ahogy fent
   is hasznltuk, s extern "C" { ... } a deklarci kapcsos zrjelek
   kztt. Az els (inline) forma egy deklarci ami egyszerre extern s
   C nyelv kirtkelst r el, mg a msodik csak a nyelvi elrst
   befolysolja. Az albbi kt deklarci ekvivalens:

extern "C" int foo;
extern "C" void bar();

   s

extern "C" {
     extern int foo;
     extern void bar();
 }

   Ahogy nincs klnbsg extern s a nem-extern fggvny
   fggvnydeklarcik kztt sem. Ez mindaddig nem jelent problmt amg
   nem deklarlsz vltozkat. Ha vltozkat deklarlsz tartsd szben,
   hogy

   extern "C" int foo;

   s

extern "C" {
    int foo;
}

   nem ugyanaz a dolog.

   Tovbbi rszleteket tallsz a [ISO14882], 7.5 fejezetben, klns
   tekintettel a 7. bekezdsre vagy a [STR2000], 9.2.4. paragrafusban.

   Mieltt brmi extra dolgot csinlnl az extern vltozkkal, ajnlott
   elolvasni a "[26]Tovbbi informci" fejezetben felsorolt
   dokumentumokat.
     _________________________________________________________________

3.3. Osztlyok betltse

Az osztlyok betltse egy kicsit komplikltabb, mert neknk az osztly egy
pldnyra van szksgnk, nem csak egy fggvnyre mutat mutatra.

Nem tudjuk ltrehozni az osztly egy pldnyt a new opertor segtsgvel,
mert az osztly nincs definilva a futtathat llomnyban, s mert nem
tudjuk a nevt.

A megolds a polimorfizmus segtsgvel addik. Egy alap interfsz osztlyt
definilunk a futtathat llomnyban virtulis tagfggvnyekkel, s egy
szrmaztatott implementcis osztlyt a modulban. ltalban az interfsz
absztrakt osztly (egy osztly absztrakt, ha minden fggvnye virtulis).

A dinamikus osztlybetltst ltalban plug-in-okban hasznljk -- Ezeknek
egy vilgosan definilt interfszt kell hasznlniuk -- Egy interfszt s az
azt implementl osztlyokat kell definilnunk.

Ezek utn - mg mindig a modulban - definilunk kt tovbbi segdfggvnyt
(gynevezett class factory functions). Az egyik fggvny ezek kzl
elkszti egy pldnyt az osztlynak, s egy arra irnytott mutatt ad
vissza. Mg a msik egy osztlyra irnytott mutatt kap (amit a factory
ksztett) s felszabadtja azt. Ezt a kt fggvnyt extern "C" direktvval
jelljk meg.

Ahhoz, hogy osztlyt tlts be modulbl csak a kt factory fggvnyt kell
betltened a dlsym segtsgvel. Szerkeszteni (link) ugyangy kell, mint
ahogy azt [27]ebben rszben tettk a hello fggvnnyel. Ezek utn mr annyi
pldnyt tudsz ltrehozni s felszabadtani az osztlybl, amennyit csak
akarsz.

   Plda 2. Egy osztly betltse

   Itt mi most egy ltalnos polygon osztlyt hasznlunk, mint interfsz
   s egy szrmaztatott triangle osztlyt, mint implementcit.

   main.cpp:
#include "polygon.hpp"
#include <iostream>
#include <dlfcn.h>

int main() {
    using std::cout;
    using std::cerr;

    // load the triangle library
    void* triangle = dlopen("./triangle.s, RTLD_LAZY);
    if (!triangle) {
        cerr << "Cannot load library: " << dlerror() << '\n';
        return 1;
    }

    // load the symbols
    create_t* create_triangle = (create_t*) dlsym(triangle, "create");
    destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, "destroy");
    if (!create_triangle || !destroy_triangle) {
        cerr << "Cannot load symbols: " << dlerror() << '\n';
        return 1;
    }

    // create an instance of the class
    polygon* poly = create_triangle();

    // use the class
    poly->set_side_length(7);
        cout << "The area is: " << poly->area() << '\n';

    // destroy the class
    destroy_triangle(poly);

    // unload the triangle library
    dlclose(triangle);
}

   polygon.hpp:
#ifndef POLYGON_HPP
#define POLYGON_HPP

class polygon {
protected:
    double side_length_;

public:
    polygon()
        : side_length_(0) {}

    void set_side_length(double side_length) {
        side_length_ = side_length;
    }

    virtual double area() const = 0;
};

// the types of the class factories
typedef polygon* create_t();
typedef void destroy_t(polygon*);

#endif

   triangle.cpp:
#include "polygon.hpp"
#include <cmath>

class triangle : public polygon {
public:
    virtual double area() const {
        return side_length_ * side_length_ * sqrt(3) / 2;
    }
};


// the class factories

extern "C" polygon* create() {
    return new triangle;
}

extern "C" void destroy(polygon* p) {
    delete p;
}

   Nhny dolgot meg kell jegyeznnk az osztlyok betltsvel
   kapcsolatban:

     * Az osztlyt ltrehoz s felszabadt fggvnyeket meg kell rnod.
       Soha ne szabadtsd fel a pldnyokat a delete opertorral a
       futtathat llomnyon bell. Mindig add vissza azokat a modulnak.
       Ez azrt szksges, mert a new s a delete C++ opertorok
       hasznlata nem felttlenl konzekvens. Ezrt lehetsges, hogy egy
       pr nlkli new vagy delete hvs az oka a memria-szivrgsnak
       vagy segmentation fault-nak. Ugyanez igaz akkor is, ha klnbz
       standard programknyvtrakat hasznlsz a modulban s futtathat
       llomnyban.
     * Az interfsz osztly dekonstruktornak virtulisnak kell lennie
       szinte minden esetben. Lehetsges egy meglehetsen ritka eset,
       amikor ez nem felttlen szksges. Ez a megkts nem okoz
       problmt, mert az ltala keletkez tbbletterhels (overhead)
       elhanyagolhat.
       Ha az alap osztlyodnak nincs szksges dekonstruktorra akkor is
       definilj egy reset (s virtual-t), klnben elbb vagy utbb
       problmid lesznek. Ezt garantlom. Tbbet tudhatsz meg errl a
       problmrl a [28]C++ FAQ lite webhelyen tallhat comp.lang.c++
       GYIK 20. fejezetbl.
     _________________________________________________________________

4. Gyakran Ismtelt Krdsek

   4.1. [29]Windowst hasznlok s nem tallom a dlfcn.h header llomnyt
          a PC-men! Mi a problma?

   4.2. [30]Ltezik brmilyen dlopen-kompatibilis illesztfellet a
          Windows LoadLibrary API-jhoz?

   4.1. Windowst hasznlok s nem tallom a dlfcn.h header llomnyt a
   PC-men! Mi a problma?

   A problma, mint mindig a Windows. Nincs dlfcn.h header Windows-on s
   nincs dlopen API sem. Van egy hasonl API a LoadLibrary fggvnnyel. A
   legtbb itt lert dolog alkalmazhat erre is. Tovbb hasznlhatod a
   libltdl (a libtool rsze) programknyvtrat, hogy "emulld" a dlopen-t
   szmos platformon.

   Olvasd el a [31]Programknyvtr HOGYAN ([32]Program Library HOWTO) 4.
   fejezett ([33]Dinamikusan betlthet (Dynamically Loaded; DL)
   programknyvtrak; [34]Dynamically Loaded (DL) Libraries). Ez tovbbi
   informcikkal szolgl olyan technikkrl, amelyekkel
   platformfggetlenl tlthetsz be programknyvtrakat s kszthetsz
   osztlyokat.

   4.2. Ltezik brmilyen dlopen-kompatibilis illesztfellet a Windows
   LoadLibrary API-jhoz?

   Nem tudok rla s nem hiszem, hogy valaha is lesz olyan, ami a dlopen
   sszes lehetsgt tmogatni fogja.

   Vannak alternatv megoldsok: libtltdl (a libtool rsze), ami a
   klnbz dinamikus betlt API-khoz nyjt egysges felletet,
   kztk a dlopen s a LoadLibrary API-khoz is. Egy msik lehetsg a
   [35]Dynamic Loading of Modules (A GLib dinamikus modul betlts).
   Hasznld ezeket a jobb platformfggetlensg biztostsa rdekben. n
   soha nem hasznltam ket, gy nem tudom megmondani neked mennyire
   stabilak s hogyan mkdnek.
     _________________________________________________________________

5. Tovbbi informci

     * A dlopen(3) kziknyv oldalai. Ez kifejti a dlopen API cljt s a
       hasznlatt.
     * A [36]Dynamic Class Loading for C++ on Linux cikk James Norton
       tollbl a [37]Linux Journal-on.
     * A kedvenc C++ referencid a extern "C"-rl, rkldsrl,
       virtulis fggvnyekrl, new s delete opertorokrl. A [STR2000]
       ajnlott.
     * [ISO14882]
     * A [38]Programknyvtr HOGYAN ([39]Program Library HOWTO) mintent
       tartalmaz, amire valaha szksged lesz statikus, megosztott s
       dinamikusan betlthet programknyvtrakkal kapcsolatban. Melegen
       ajnlott.
     * A [40]Linux GCC HOWTO-bl tbbet tudhatsz meg arrl, hogyan
       kszthetsz programknyvtrakat GCC-vel.
     _________________________________________________________________

Irodalomjegyzk

   ISO14482 ISO/IEC 14482-1998 -- The C++ Programming Language. PDF s
   nyomtatott knyv formjban is elrhet a
   [41]http://webstore.ansi.org/ webhelyen.

   STR2000 Bjarne Stroustrup The C++ Programming Language, Special
   Edition. ISBN 0-201-70073-5. Addison-Wesley.

References

   1. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#intro
   2. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#copyright
   3. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#disclaimer
   4. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#credits
   5. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#feedback
   6. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#AEN85
   7. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#AEN106
   8. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#theproblem
   9. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#mangling
  10. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#AEN137
  11. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#thesolution
  12. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#externC
  13. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#loadingfunctions
  14. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#loadingclasses
  15. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#faq
  16. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#seealso
  17. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#AEN304
  18. http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/
  19. mailto:joyg (at) us.ibm.com
  20. mailto:stimitis (at) idcomm.com
  21. mailto:aaron@isotton.com
  22. mailto: szferi[kukac]einstein.ki.iif[pont]hu
  23. mailto:dacas@freemail.hu_NO_SPAM
  24. http://tldp.fsf.hu/index.html
  25. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#mangling
  26. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#seealso
  27. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#loadingfunctions
  28. http://www.parashift.com/c++-faq-lite/
  29. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#AEN249
  30. file://localhost/home/dacas/tldp/convert/C++-dlopen-hu.html#AEN265
  31. http://tldp.fsf.hu/HOWTO/Program-Library-HOWTO-hu/index.html
  32. http://www.dwheeler.com/program-library
  33. http://tldp.fsf.hu/HOWTO/Program-Library-HOWTO-hu/dl-libraries.html
  34. http://www.dwheeler.com/program-library/Program-Library-HOWTO/dl-libraries.html
  35. http://developer.gnome.org/doc/API/glib/glib-dynamic-loading-of-modules.html
  36. http://www.linuxjournal.com/article.php?sid=3687
  37. http://www.linuxjournal.com/
  38. http://tldp.fsf.hu/HOWTO/Program-Library-HOWTO-hu/index.html
  39. http://www.dwheeler.com/program-library
  40. http://tldp.org/HOWTO/GCC-HOWTO/index.html
  41. http://webstore.ansi.org/
