aaron@isotton.com
2003.08.12
Verziótörténet | ||
---|---|---|
Verzió: 1.03 | 2003.08.12 | Átdolgozta: AI |
Referencia hozzáadása a GLib dinamikus modul betöltőjéről. Köszönet érte G. V. Sriraam-nak. | ||
Verzió: 1.02 | 2002.12.08 | Átdolgozta: AI |
GYIK hozzáadása. Kisebb változtatások. | ||
Verzió: 1.01 | 2002.06.30 | Átdolgozta: AI |
Frissített magyarázat a virtuális dekonstuktorokról. Kisebb változtatások. | ||
Verzió: 1.00 | 2002.06.19 | Átdolgozta: AI |
A „Szerzői jog és licenc” fejezet az elejére került. „A dokumentumban használt kifejezések” fejezet hozzáadása. Kisebb változtatások. | ||
Verzió: 0.97 | 2002.06.19 | Átdolgozta: JYG |
Egy kis szótár, valamint mondat-szintű változtatások. | ||
Verzió: 0.96 | 2002.06.12 | Átdolgozta: AI |
Irodalomjegyzék hozzáadása. Az extern függvények és változók leírásának javítása. | ||
Verzió: 0.95 | 2002.06.11 | Átdolgozta: AI |
Kisebb javítások. |
Ez a HOGYAN elsődleges a http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ webhelyen található meg.
Örömmel mondok köszönetet az alábbi személyeknek (abc sorrendben):
Joy Y Goodreau <joyg (at) us.ibm.com> a szerkesztésért.
D. Stimitis <stimitis (at) idcomm.com> rámutatott néhány kérdésre a formázással és a név szétszedéssel kapcsolatban valamit az extern "C"-vel kapcsolatban.
Visszajelzést szívesen fogadok. A megjegyzéseidet, kritikádat és a hozzájárulásaidat a <aaron@isotton.com> címre küldheted.
A magyar fordítást Szalai Ferenc készítette (2004.04.17). A lektorálást Daczi László végezte el (2004.05.04). Utoljára javítva 2004.05.05.-én (r2). A dokumentum legfrissebb változata megtalálható a Magyar Linux Dokumentációs Projekt honlapján.
A C nyelvben a program könyvtárak betöltése igen egyszerű (dlopen, dlsym és dlclose meghívása elegendő). C++-al ez egy kicsit bonyolultabb. A C++ program könyvtárak betöltésének nehézséget részint a „nevek szétszedése”, részben pedig az a tény okozza, hogy a dlopen API C-ben lett írva, így nem teszi lehetővé osztályok egyszerű betöltését.
Mielőtt bemutatnánk a programkönyvtárak betöltését, C++-ban megvizsgáljuk a „név szétszedési” problémát egy kicsit alaposabban. Azt ajánlom akkor is olvasd el ezt a részt, ha nem érdekel, mert segít megérteni mi is a probléma és mi a megoldása.
Példa 1. Egy függvény betöltése
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.so", 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, "hello"); 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 << "hello" << '\n'; } |
![]() | Két típusa létezik az extern "C" deklarációnak: extern "C" ahogy fent is használtuk, és extern "C" { … } a deklaráció kapcsos zárójelek között. Az első (inline) forma egy deklaráció ami egyszerre extern és C nyelvű kiértékelést ír elő, míg a második csak a nyelvi előírást befolyásolja. Az alábbi két deklaráció ekvivalens: és Ahogy nincs különbség extern és a nem-extern függvény függvénydeklarációk között sem. Ez mindaddig nem jelent problémát amíg nem deklarálsz változókat. Ha változókat deklarálsz tartsd észben, hogy és nem ugyanaz a dolog.További részleteket találsz a [ISO14882], 7.5 fejezetében, különös tekintettel a 7. bekezdésre vagy a [STR2000], 9.2.4. paragrafusában. Mielőtt bármi extra dolgot csinálnál az extern változókkal, ajánlott elolvasni a „További információ” fejezetben felsorolt dokumentumokat. |
Ahhoz, hogy osztályt tölts be modulból csak a két factory függvényt kell betöltened a dlsym segítségével. Szerkeszteni (link) ugyanúgy kell, mint ahogy azt ebben részben tettük a hello függvénnyel. Ezek után már annyi példányt tudsz létrehozni és felszabadítani az osztályból, amennyit csak akarsz.
Példa 2. Egy osztály betöltése
Itt mi most egy általános polygon osztályt használunk, mint interfész és egy származtatott triangle osztályt, mint implementációt.
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.so", 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; } |
Néhány dolgot meg kell jegyeznünk az osztályok betöltésével kapcsolatban:
Ha az alap osztályodnak nincs szükséges dekonstruktorra akkor is definiálj egy üreset (és virtual-t), különben előbb vagy utóbb problémáid lesznek. Ezt garantálom. Többet tudhatsz meg erről a problémáról a C++ FAQ lite webhelyen található comp.lang.c++ GYIK 20. fejezetéből.
Olvasd el a Programkönyvtár HOGYAN (Program Library HOWTO) 4. fejezetét (Dinamikusan betölthető (Dynamically Loaded; DL) programkönyvtárak; Dynamically Loaded (DL) Libraries). Ez további információkkal szolgál olyan technikákról, amelyekkel platformfüggetlenül tölthetsz be programkönyvtárakat és készíthetsz osztályokat.
Vannak alternatív megoldások: libtltdl (a libtool része), ami a különböző dinamikus betöltő API-khoz nyújt egységes felületet, köztük a dlopen és a LoadLibrary API-khoz is. Egy másik lehetőség a Dynamic Loading of Modules (A GLib dinamikus modul betöltés). Használd ezeket a jobb platformfüggetlenség biztosítása érdekében. Én soha nem használtam őket, így nem tudom megmondani neked mennyire stabilak és hogyan működnek.
A dlopen(3) kézikönyv oldalai. Ez kifejti a dlopen API célját és a használatát.
A Dynamic Class Loading for C++ on Linux cikk James Norton tollából a Linux Journal-on.
A kedvenc C++ referenciád a extern "C"-ról, öröklődésről, virtuális függvényekről, new és delete operátorokról. A [STR2000] ajánlott.
[ISO14882]
A Programkönyvtár HOGYAN (Program Library HOWTO) mintent tartalmaz, amire valaha szükséged lesz statikus, megosztott és dinamikusan betölthető programkönyvtárakkal kapcsolatban. Melegen ajánlott.
A Linux GCC HOWTO-ból többet tudhatsz meg arról, hogyan készíthetsz programkönyvtárakat GCC-vel.
ISO14482 ISO/IEC 14482-1998 — The C++ Programming Language. PDF és nyomtatott könyv formájában is elérhető a http://webstore.ansi.org/ webhelyen.