From 348e4fad8e3d556d3769b5551cf6bde683722923 Mon Sep 17 00:00:00 2001 From: gferg <> Date: Thu, 16 Mar 2006 16:10:42 +0000 Subject: [PATCH] moved --- LDP/howto/docbook/C++-dlopen/C++-dlopen.xml | 782 +++++++++++++++++++ LDP/howto/docbook/C++-dlopen/examples.tar.gz | Bin 0 -> 1543 bytes 2 files changed, 782 insertions(+) create mode 100644 LDP/howto/docbook/C++-dlopen/C++-dlopen.xml create mode 100644 LDP/howto/docbook/C++-dlopen/examples.tar.gz diff --git a/LDP/howto/docbook/C++-dlopen/C++-dlopen.xml b/LDP/howto/docbook/C++-dlopen/C++-dlopen.xml new file mode 100644 index 00000000..ffdc7a91 --- /dev/null +++ b/LDP/howto/docbook/C++-dlopen/C++-dlopen.xml @@ -0,0 +1,782 @@ + + +
+ + + + C++ dlopen mini HOWTO + + + Aaron + Isotton + +
aaron@isotton.com
+
+
+ + 2006-03-16 + + + + + 1.10 + 2006-03-16 + AI + + Changed the license from the GFDL to the GPL. Fixed usage + of dlerror; thanks to Carmelo Piccione. Using a virtual destructor + in the example; thanks to Joerg Knobloch. Added Source Code + section. Minor fixes. + + + + + 1.03 + 2003-08-12 + AI + Added reference to the GLib Dynamic Module + Loader. Thanks to G. V. Sriraam for the pointer. + + + + 1.02 + 2002-12-08 + AI + Added FAQ. Minor changes + + + + 1.01 + 2002-06-30 + AI + Updated virtual destructor explanation. Minor changes. + + + + 1.00 + 2002-06-19 + AI + Moved copyright and license section to the + beginning. Added terms section. Minor changes. + + + + 0.97 + 2002-06-19 + JYG + Entered minor grammar and sentence level changes. + + + + 0.96 + 2002-06-12 + AI + Added bibliography. Corrected explanation of extern + functions and variables. + + + + 0.95 + 2002-06-11 + AI + Minor improvements. + + + + + + How to dynamically load C++ functions and classes using + the dlopen API. + + +
+ + +
+ Introduction + + + A question which frequently arises among Unix C++ programmers is + how to load C++ functions and classes dynamically using the + dlopen API. + + + In fact, that is not always simple and needs some + explanation. That's what this mini HOWTO does. + + An average understanding of the C + and C++ programming language and of the + dlopen API is necessary to understand this + document. + + This HOWTO's master location is . + + + +
+ Disclaimer + + + No liability for the contents of this document can be + accepted. Use the concepts, examples and information at your + own risk. There may be errors and inaccuracies, that could be + damaging to your system. Proceed with caution, and although + this is highly unlikely, the author(s) do not take any + responsibility. + + + + All copyrights are held by their by their respective owners, + unless specifically noted otherwise. Use of a term in this + document should not be regarded as affecting the validity of + any trademark or service mark. Naming of particular products + or brands should not be seen as endorsements. + +
+ +
+ Credits / Contributors + + + In this document, I have the pleasure of acknowledging (in + alphabetic order): + + + + + + Joy Y Goodreau joyg (at) us.ibm.com for + her editing. + + + + D. Stimitis stimitis (at) idcomm.com + for pointing out a few issues with the formatting and the + name mangling, as well as pointing out a few subtleties of + extern "C". + + Many unnamed others pointing out errors or giving tips to + improve this howto. You know who you are! + + + + + +
+ +
+ Feedback + + + Feedback is most certainly welcome for this document. Send + your additions, comments and criticisms to the following email + address: aaron@isotton.com. + +
+ +
+ Terms Used in this Document + + + + dlopen API + + The dlclose, + dlerror, + dlopen and + dlsym functions as described in the + dlopen(3) man page. + + Notice that we use + dlopen to refer to + the individual dlopen + function, and + dlopen API to refer + to the entire API. + + + + +
+ + +
+ +
+ The Problem + + At some time you might have to load a library (and use its + functions) at runtime; this happens most often when you are + writing some kind of plug-in or module architecture for your + program. + + In the C language, loading a library is very simple (calling + dlopen, dlsym and + dlclose is enough), with C++ this is a bit + more complicated. The difficulties of loading a C++ library + dynamically are partially due to name + mangling, and partially due to the fact that the + dlopen API was written with C in mind, thus + not offering a suitable way to load classes. + + Before explaining how to load libraries in C++, let's better + analyze the problem by looking at name mangling in more + detail. I recommend you read the explanation of name mangling, + even if you're not interested in it because it will help you + understanding why problems occur and how to solve them. + +
+ Name Mangling + + In every C++ program (or library, or object file), all + non-static functions are represented in the binary file as + symbols. These symbols are special text + strings that uniquely identify a function in the program, + library, or object file. + + In C, the symbol name is the same as the function name: + the symbol of strcpy will be + strcpy, and so on. This is + possible because in C no two non-static functions can have the + same name. + + Because C++ allows overloading (different functions with + the same name but different arguments) and has many features C + does not — like classes, member functions, exception + specifications — it is not possible to simply use the + function name as the symbol name. To solve that, C++ uses + so-called name mangling, which transforms + the function name and all the necessary information (like the + number and size of the arguments) into some weird-looking + string which only the compiler knows about. The mangled name + of foo might look like + foo@4%6^, for example. Or it + might not even contain the word foo. + + One of the problems with name mangling is that the C++ + standard (currently ISO14882) does not + define how names have to be mangled; thus every compiler + mangles names in its own way. Some compilers even change their + name mangling algorithm between different versions (notably + g++ 2.x and 3.x). Even if you worked out how your particular + compiler mangles names (and would thus be able to load + functions via dlsym), this would most + probably work with your compiler only, and might already be + broken with the next version. + +
+ +
+ Classes + + Another problem with the dlopen API + is the fact that it only supports loading + functions. But in C++ a library often + exposes a class which you would like to use in your + program. Obviously, to use that class you need to create an + instance of it, but that cannot be easily done. + +
+ +
+ +
+ The Solution + +
+ <literal>extern "C"</literal> + + C++ has a special keyword to declare a function with C + bindings: extern "C". A function declared + as extern "C" uses the function name as + symbol name, just as a C function. For that reason, only + non-member functions can be declared as extern + "C", and they cannot be overloaded. + + Although there are severe limitations, extern + "C" functions are very useful because they can be + dynamically loaded using dlopen just like + a C function. + + This does not mean that functions + qualified as extern "C" cannot contain C++ + code. Such a function is a full-featured C++ function which + can use C++ features and take any type of argument. + +
+ +
+ Loading Functions + + In C++ functions are loaded just like in C, with + dlsym. The functions you want to load + must be qualified as extern "C" to avoid + the symbol name being mangled. + + + Loading a Function + + main.cpp: + +#include + +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)(); + + // reset errors + dlerror(); + hello_t hello = (hello_t) dlsym(handle, "hello"); + const char *dlsym_error = dlerror(); + if (dlsym_error) { + cerr << "Cannot load symbol 'hello': " << dlsym_error << + '\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: + + +extern "C" void hello() { + std::cout << "hello" << '\n'; +} +]]> + + + The function hello is defined in + hello.cppas extern + "C"; it is loaded in main.cpp + with the dlsym call. The function must be + qualified as extern "C" because otherwise + we wouldn't know its symbol name. + + + There are two different forms of the + extern "C" declaration: extern + "C" as used above, and extern "C" { + … } with the declarations between the + braces. The first (inline) form is a declaration with extern + linkage and with C language linkage; the second only affects + language linkage. The following two declarations are thus + equivalent: + + + extern "C" int foo; +extern "C" void bar(); + + + and + + extern "C" { + extern int foo; + extern void bar(); +} + + + As there is no difference between an + extern and a + non-extern function + declaration, this is no problem as long as you are not + declaring any variables. If you declare + variables, keep in mind that + + + extern "C" int foo; + + and + + extern "C" { + int foo; +} + + + are not the same thing. + + For further clarifications, refer to + ISO14882, 7.5, with special attention + to paragraph 7, or to STR2000, + paragraph 9.2.4. + + Before doing fancy things with extern variables, peruse + the documents listed in the see + also section. + + + +
+ +
+ Loading Classes + + Loading classes is a bit more difficult because we need + an instance of a class, not just a + pointer to a function. + + We cannot create the instance of the class using + new because the class is not defined in the + executable, and because (under some circumstances) we don't + even know its name. + + The solution is achieved through polymorphism. We define a + base, interface class with virtual + members in the executable, and a derived, + implementation class in the + module. Generally the interface class is + abstract (a class is abstract if it has pure virtual + functions). + + As dynamic loading of classes is generally used for + plug-ins — which must expose a clearly defined interface + — we would have had to define an interface and derived + implementation classes anyway. + + Next, while still in the module, we define two additional helper + functions, known as class factory + functions. One of these functions creates an instance of + the class and returns a pointer to it. The other function takes a + pointer to a class created by the factory and destroys + it. These two functions are qualified as extern + "C". + + To use the class from the module, load the two factory + functions using dlsym just as we loaded the the hello + function; then, we can create and destroy as many + instances as we wish. + + + Loading a Class + + Here we use a generic polygon + class as interface and the derived class + triangle as implementation. + + main.cpp: + +#include + +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; + } + + // reset errors + dlerror(); + + // load the symbols + create_t* create_triangle = (create_t*) dlsym(triangle, "create"); + const char* dlsym_error = dlerror(); + if (dlsym_error) { + cerr << "Cannot load symbol create: " << dlsym_error << '\n'; + return 1; + } + + destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, "destroy"); + dlsym_error = dlerror(); + if (dlsym_error) { + cerr << "Cannot load symbol destroy: " << dlsym_error << '\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: + + + triangle.cpp: + + +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; +} +]]> + + + + There are a few things to note when loading classes: + + + + You must provide both a creation + and a destruction function; you must + not destroy the instances using + delete from inside the executable, but + always pass it back to the module. This is due to the fact + that in C++ the operators new and + delete may be overloaded; this would + cause a non-matching new and + delete to be called, which could cause + anything from nothing to memory leaks and segmentation + faults. The same is true if different standard libraries + are used to link the module and the executable. + + + + The destructor of the interface class should be + virtual in any case. There might be + very rare cases where that would not be necessary, but it + is not worth the risk, because the additional overhead can + generally be ignored. + If your base class needs no destructor, define an + empty (and virtual) one anyway; + otherwise you will have problems + sooner or later; I can guarantee you that. You can read + more about this problem in the comp.lang.c++ FAQ at , in + section 20. + + + +
+
+ +
+ Source Code + + You can download all the source code presented in this howto as an + archive: . + +
+ +
+ Frequently Asked Questions + + + + I'm using Windows and I can't find the + dlfcn.h header file! What's the problem? + + + The problem is that Windows doesn't have the + dlopen API, and thus there is no + dlfcn.h header. There is a similar API + around the LoadLibrary function, and + most of what is written here applies to it, too. Please refer to the + Microsoft Developer Network + Website for more information. + + + + + + + + Is there some kind of dlopen-compatible + wrapper for the Windows LoadLibrary + API? + + + + + I don't know of any, and I don't think there'll ever be one + supporting all of dlopen's options. + + There are alternatives though: libtltdl (a part of libtool), + which wraps a variety of different dynamic loading APIs, among + others dlopen and + LoadLibrary. Another one is the Dynamic + Module Loading functionality of GLib. You can use one + of these to ensure better possible cross-platform compatibility. + I've never used any of them, so I can't tell you how stable they + are and whether they really work. + + You should also read section 4, Dynamically + Loaded (DL) Libraries, of the Program Library + HOWTO for more techniques to load libraries and + create classes independently of your platform. + + + + +
+ +
+ See Also + + + + The dlopen(3) man page. It explains + the purpose and the use of the dlopen + API. + + + + The article + Dynamic Class Loading for C++ on + Linux by James Norton published on the + Linux + Journal. + + + + Your favorite C++ reference about extern + "C", inheritance, virtual functions, + new and delete. I + recommend STR2000. + + + + ISO14882 + + + + The Program Library + HOWTO, which tells you most things you'll ever need + about static, shared and dynamically loaded libraries and how + to create them. Highly recommended. + + + + The Linux GCC + HOWTO to learn more about how to create libraries + with GCC. + + + + +
+ + + + + ISO14482 ISO/IEC 14482-1998 — The + C++ Programming Language. Available as + PDF and as printed book from . + + + + STR2000 + Stroustrup Bjarne + The C++ Programming Language, Special + Edition. + ISBN 0-201-70073-5. + Addison-Wesley. + + + + +
diff --git a/LDP/howto/docbook/C++-dlopen/examples.tar.gz b/LDP/howto/docbook/C++-dlopen/examples.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..50b2c4365d98a7e2c38c933b6afbe369071ba0b9 GIT binary patch literal 1543 zcmV+i2Kf0OiwFRDco{?h1MOICZ`(Ey_SfoH-0T6d-P)FATLzr8Sdn4r0IvzQ3~Po0 z1}o9AFq!lux>-NHdnAS~?h1lFsN2pYm$nxqkD zDG-587DB8hz242uO*fy>E;{Hf_>JIc4`X&z%uW`wBOUgf1{$97)ol`8F9dk5>viyt z56?-$8T_dHzzNCz{myXv4DF^-Kv|0YShJ8Ovd3pHe}%J)Y1eUz?LUDfiO^)Vf(4CZ z-c7ml=-cM$t5+?MpC6{r&wgn^heKgfT6E$tcAUa)l6%0KyIrIUl3;hxRbgUSI6+Ja zn>de>C3NOxFx@Msd-3A@<<$gaL+4Z1U+2H>!spmkRqV?DzBi~LL1c|wzc2IO_lGwB z4}nI+f_NQLIEi>F5=t;J^Oj| znjIZG?>~75M+f8Y0f&Hw(`Q~W=+`F{x9mH%Z~7|#RNUEq-rF(C<0 zp91SNV%OzaaJ*GWljPWurTVNeZWJM1^4IJ&tLJTcJ&@%YJ;%|Tge13B+jFeVoEJpc z?RKSg)+jrq+OWWT2i{_y<{_H(Zm(!ue*!;WPQRZ`pZ|W7Il%B~of42peM z9VU!%p?a40Y69}GLyIKg2~LMT`3mcViZz~|eO2CU^mh4%$JHTDu~N>T ztjkAg3{%{$Xh`SkOm4Pi{YYpE>L{ZuY;8}-GhY8FngA%< z>$z2cw>JR+-dmt8+s&j?In@>S*?bxeJ~XFtCi0OU$!JGGC)z=V>O_Ze5c8Dg zoo+pB1=cBEbOi_wAy?N|5(n#;2)v?h>{b%T<&HDfA*aLRieK54`?v2YR%g!gO4Hre zFb+wf`T6htTi*Zv*j4X;&%XZ;0loe!9^YQ$t7-B1uK>I5|Nda0`G4&7as5Z0?^^yp z1RBwtWt?(xKD|0Se>r<`ap5$uAY!yqhVN36rjYLvJl9tV7c{{4{X`vNeEkN=H;qC% ziz&Mniy5-g3Jaq^wa87IEqzQ+D$ScN(#3nlWN)KHtVs-iYooF%BR?d$nPJ=9j&4$q z83j4Z__rX4O3>UHKGF%sRowR!Ts)U?M0nC?XM9G*X(5!TshN{N@Fb$CQ}A@&`8EXT zO3<0eIHN-1A;mivzr~uOZN}vd%ED-V7!uI=|0VUmkyq+}zAx|po_+rx1Xll(+uzXt z3?c-PM1)<(bhjMnZOVa$>7?|t5nz`=NW|#qH*ez##h%ap}9wcUpy?+gtzsnTY0~ z1wHTzx;BV-lY0&6a)W-ga*;=6^hOUSdvk56o;f*dYKB$eA*9)P2dl3@?bP}I<@7(V z?+=Uo$D991>3^Qh|3hGB{_jr~H03aTu9)J9lJ#_zDeM_McZaqoWxb-wP7&&(g}sN0 zZuf|Ps%`N$C|?QXc$>Pi(C3QECs0>)+Y((H_94-!Xm=`f50yXlW2asIG{#z1-!a&{ zvKZ|?Mwo~Am?3HnP)-uwe<8xvAS|GjC!+ZbZp$Co`HfXK#oTo+C{~R-&o*DbV?+AX zg5%{v(JtQV^C2nYoQn0BieUNhHv(=hlq5s5i|oTGTxgp*8NUL`w6L(Su&}VOu&}VO tu&}VOu&}VOu&}VOu&}VOu&}VOu&}VOu&}VOu(0@I_y@W_2UY-3000p)A1?p^ literal 0 HcmV?d00001