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. |
UNIX C++ programoz�kban felmer�l� gyakori k�rd�s, hogyan t�ltsenek be dinamikusan C++ f�ggv�nyeket �s oszt�lyokat a dlopen haszn�lat�val.
T�ny, hogy nem minden esetben egyszer� ez, �s n�mi magyar�zatot ig�nyel. Ez van le�rva ebben a mini-HOGYANban.
Egy �tlagos C �s C++ programoz�si nyelv ismeret valamint a dlopen API ismerete sz�ks�ges ahhoz, hogy meg�rthesd ezt a dokumentumot.
Ez a HOGYAN els�dleges a http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ webhelyen tal�lhat� meg.
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 verzi�j�ban foglalt felt�telek keretein bel�l m�solhat�, terjeszthet� �s/vagy m�dos�that�; invari�ns fejezet, els� �s h�ts� bor�t�lapsz�veg nincsen.
A dokumentum tartalm��rt nincs felel�ss�gv�llal�s. Az elgondol�sokat, p�ld�kat �s inform�ci�kat a saj�t felel�ss�gedre haszn�ld. El�fordulhatnak hib�k �s pontatlans�gok, amelyek a rendszered s�r�l�s�t okozhatj�k. Minden �vatoss�g ellen�re b�rmily hihetetlen, a szerz�(k) semmilyen felel�ss�get nem v�llal(nak).
Minden szerz�i jog fenntartva az eredeti tulajdonos�nak, amennyiben m�sk�nt nincs jel�lve. A dokumentumban haszn�lt szakkifejez�sek semmilyen p�rhuzamot nem k�pviselnek v�djegyekre, szerv�z m�rk�kra vonatkoz�lag. Egyedi alkot�sok vagy v�djegyek neves�t�se nem hozz�j�rul�sok.
�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 <[email protected]> c�mre k�ldheted.
A dlclose, dlerror, dlopen �s dlsym f�ggv�nyek, amik le�r�sa a dlopen(3) k�zik�nyv oldalon tal�lhat�.
Megjegyezz�k, hogy mi a "dlopen" kifejez�st a dlopen f�ggv�nyre mag�ra, �s a "dlopen API" kifejez�st az eg�sz API-ra haszn�ljuk.
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.
N�ha fut�sid�ben kellene bet�lteni programk�nyvt�rakat (�s haszn�lni a f�ggv�nyeiket). Ez legink�bb akkor sz�ks�ges, ha valamilyen plug-in vagy modul architekt�r�j� programot �rsz.
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.
Minden C++ programban (vagy programk�nyvt�rban vagy t�rgyk�d �llom�nyban) minden nem statikus f�ggv�ny a bin�ris �llom�nyban szimb�lumokkal van reprezent�lva. Ezek a szimb�lumok speci�lis karaktersorozatok, amik egy�rtelm�en azonos�tj�k a f�ggv�nyt a programban, programk�nyvt�rban vagy t�rgyk�d �llom�nyban.
C-ben a szimb�lum nevek megegyeznek a f�ggv�nyek neveivel: az strcpy f�ggv�ny szimb�luma strcpy �s �gy tov�bb. Ez az�rt lehets�ges, mert C-ben k�t nem statikus f�ggv�nynek nem lehet azonos a neve.
Mivel a C++ enged�lyezi az �tdefini�l�st (overloading - k�l�nb�z� f�ggv�nyek azonos n�vvel, de k�l�nb�z� argumentumokkal), valamint sz�mos �j tulajdons�ga van, ami a C-nek nincs — mint oszt�lyok, tagf�ggv�nyek, kiv�tel kezel�s — ez�rt nem lehets�ges a f�ggv�nyek nev�t egyszer�en szimb�lumn�vnek haszn�lni. A C++ ezt az probl�m�t az �gynevezett „n�v sz�tszed�ssel” (mangling) oldja meg. Ez �gy m�k�dik, hogy a a f�ggv�nyek �s egy�b sz�ks�ges inform�ci�k (mint az argumentumok sz�ma �s m�rete) alapj�n l�trehoz egy csak a ford�t� sz�m�ra �rtelmes karaktersorozatot, amit az szimb�lum n�vnek tud haszn�lni. A foo f�ggv�ny ilyen m�don el��ll�tott neve �gy n�zhet ki p�ld�ul: foo@4%6^. Vagy nem is felt�tlen kell tartalmaznia a "foo" sz�t mag�t.
Az egyik probl�ma ezzel az elj�r�ssal az, hogy a C++ standard (jelenleg [ISO14882]) nem defini�lja ennek a menet�t. �gy minden ford�t� a saj�t m�dszer�t haszn�lja. N�h�ny ford�t� meg is v�ltoztatja az algoritmust verzi�r�l verzi�ra (k�l�n�sen a g++ 2.x �s 3.x k�z�tt). Ez�rt ha ki is tal�ltad, hogy a te ford�t�d hogyan is m�k�dik e tekintetben (�s �gy be fogod tudni t�lteni a f�ggv�nyeidet a dlsym seg�ts�g�vel) ez val�sz�n�leg csak a te ford�t�ddal fog m�k�dni �s haszn�lhatatlan lesz annak k�vetkez� verzi�j�val.
A C++-nak van egy speci�lis kulcsszava arra, hogy f�ggv�nyeket C k�t�ssel defini�ljuk. Ez az extern "C". Az a f�ggv�ny ami extern "C"-k�nt lett defini�lva annak f�ggv�nyneve szimb�lumk�nt haszn�lhat� ak�rcsak egy C f�ggv�nynek. Ez�rt csak nem-tagf�ggv�nyek deklar�lhat�k extern "C" seg�ts�g�vel, �s ezeket nem lehet �tdefini�lni.
Hab�r van n�h�ny megk�t�s az extern "C" f�ggv�nyekre, m�gis igen hasznosak, mivel dinamikusan bet�lthet�ek a dlopen seg�ts�g�vel ak�rcsak a C f�ggv�nyek.
Ez nem jelenti azt, hogy az extern "C"-vel defini�lt f�ggv�nyek nem tartalmazhatnak C++ k�dot. Az ilyen f�ggv�nyek teljes �rt�k� C++ f�ggv�nyek, kihaszn�lhatj�k a C++ lehet�s�geit �s b�rmilyen t�pus� argumentummal rendelkezhetnek.
C++ a f�ggv�nyek �gy t�lthet�ek be mint C-ben; a dlsym seg�ts�g�vel. A bet�lteni k�v�nt f�ggv�nyeket extern "C"-vel kell jel�ln�d, hogy a C-szer� szimb�lum n�vk�pz�st kik�nyszer�tsd.
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'; } |
A hello f�ggv�ny a hello.cpp �llom�nyban van defini�lva, mint extern "C". A main.cpp-ben t�lt�dik be a dlsym h�v�ssal. A f�ggv�nyt extern "C"-vel kell megjel�lni, mert k�l�nben nem tudjuk biztosan a hozz� tartoz� szimb�lumnevet.
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. |
Az oszt�lyok bet�lt�se egy kicsit komplik�ltabb, mert nek�nk az oszt�ly egy p�ld�ny�ra van sz�ks�g�nk, nem csak egy f�ggv�nyre mutat� mutat�ra.
Nem tudjuk l�trehozni az oszt�ly egy p�ld�ny�t a new oper�tor seg�ts�g�vel, mert az oszt�ly nincs defini�lva a futtathat� �llom�nyban, �s mert nem tudjuk a nev�t.
A megold�s a polimorfizmus seg�ts�g�vel ad�dik. Egy alap interf�sz oszt�lyt defini�lunk a futtathat� �llom�nyban virtu�lis tagf�ggv�nyekkel, �s egy sz�rmaztatott implement�ci�s oszt�lyt a modulban. �ltal�ban az interf�sz absztrakt oszt�ly (egy oszt�ly absztrakt, ha minden f�ggv�nye virtu�lis).
A dinamikus oszt�lybet�lt�st �ltal�ban plug-in-okban haszn�lj�k — Ezeknek egy vil�gosan defini�lt interf�szt kell haszn�lniuk — Egy interf�szt �s az azt implement�l� oszt�lyokat kell defini�lnunk.
Ezek ut�n - m�g mindig a modulban - defini�lunk k�t tov�bbi seg�df�ggv�nyt (�gynevezett class factory functions). Az egyik f�ggv�ny ezek k�z�l elk�sz�ti egy p�ld�ny�t az oszt�lynak, �s egy arra ir�ny�tott mutat�t ad vissza. M�g a m�sik egy oszt�lyra ir�ny�tott mutat�t kap (amit a factory k�sz�tett) �s felszabad�tja azt. Ezt a k�t f�ggv�nyt extern "C" direkt�v�val jel�lj�k meg.
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:
Az oszt�lyt l�trehoz� �s felszabad�t� f�ggv�nyeket meg kell �rnod. Soha ne szabad�tsd fel a p�ld�nyokat a delete oper�torral a futtathat� �llom�nyon bel�l. Mindig add vissza azokat a modulnak. Ez az�rt sz�ks�ges, mert a new �s a delete C++ oper�torok haszn�lata nem felt�tlen�l konzekvens. Ez�rt lehets�ges, hogy egy p�r n�lk�li new vagy delete h�v�s az oka a mem�ria-sziv�rg�snak vagy segmentation fault-nak. Ugyanez igaz akkor is, ha k�l�nb�z� standard programk�nyvt�rakat haszn�lsz a modulban �s futtathat� �llom�nyban.
Az interf�sz oszt�ly dekonstruktor�nak virtu�lisnak kell lennie szinte minden esetben. Lehets�ges egy meglehet�sen ritka eset, amikor ez nem felt�tlen sz�ks�ges. Ez a megk�t�s nem okoz probl�m�t, mert az �ltala keletkez� t�bbletterhel�s (overhead) elhanyagolhat�.
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.
A probl�ma, mint mindig a Windows. Nincs dlfcn.h header Windows-on �s nincs dlopen API sem. Van egy hasonl� API a LoadLibrary f�ggv�nnyel. A legt�bb itt le�rt dolog alkalmazhat� erre is. Tov�bb� haszn�lhatod a libltdl (a libtool r�sze) programk�nyvt�rat, hogy "emul�ld" a dlopen-t sz�mos platformon.
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.
Nem tudok r�la �s nem hiszem, hogy valaha is lesz olyan, ami a dlopen �sszes lehet�s�g�t t�mogatni fogja.
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.