You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1621 lines
28 KiB
1621 lines
28 KiB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>KSquirrel: development</title>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<meta name='Author' content='Baryshev Dmitry/Krasu'>
|
|
|
|
<link rel="stylesheet" href="styles.css" type="text/css">
|
|
</head>
|
|
<body>
|
|
|
|
<DIV
|
|
CLASS="ARTICLE"
|
|
><DIV
|
|
CLASS="TITLEPAGE"
|
|
><H1
|
|
CLASS="title"
|
|
><A
|
|
NAME="AEN2"
|
|
></A
|
|
>C++ dlopen mini HOWTO</H1
|
|
><H3
|
|
CLASS="author"
|
|
><A
|
|
NAME="AEN4"
|
|
>Aaron Isotton</A
|
|
></H3
|
|
><DIV
|
|
CLASS="affiliation"
|
|
><DIV
|
|
CLASS="address"
|
|
><P
|
|
CLASS="address"
|
|
><TT
|
|
CLASS="email"
|
|
><<A
|
|
HREF="mailto:aaron@isotton.com"
|
|
>aaron@isotton.com</A
|
|
>></TT
|
|
></P
|
|
></DIV
|
|
></DIV
|
|
><P
|
|
CLASS="pubdate"
|
|
>2003-08-12<BR></P
|
|
><DIV
|
|
CLASS="revhistory"
|
|
><TABLE
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
><TR
|
|
><TH
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
COLSPAN="3"
|
|
><B
|
|
>Revision History</B
|
|
></TH
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 1.03</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2003-08-12</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: AI</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Added reference to the GLib Dynamic Module
|
|
Loader. Thanks to G. V. Sriraam for the pointer.</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 1.02</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2002-12-08</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: AI</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Added FAQ. Minor changes</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 1.01</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2002-06-30</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: AI</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Updated virtual destructor explanation. Minor changes.</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 1.00</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2002-06-19</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: AI</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Moved copyright and license section to the
|
|
beginning. Added terms section. Minor changes.</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 0.97</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2002-06-19</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: JYG</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Entered minor grammar and sentence level changes.</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 0.96</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2002-06-12</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: AI</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Added bibliography. Corrected explanation of extern
|
|
functions and variables.</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revision 0.95</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>2002-06-11</TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
>Revised by: AI</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
COLSPAN="3"
|
|
>Minor improvements.</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
><DIV
|
|
CLASS="abstract"
|
|
><A
|
|
NAME="AEN47"
|
|
></A
|
|
><P
|
|
></P
|
|
><P
|
|
>How to dynamically load C++ functions and classes using
|
|
the <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API.</P
|
|
><P
|
|
></P
|
|
></DIV
|
|
></DIV
|
|
><HR></DIV
|
|
><DIV
|
|
CLASS="TOC"
|
|
><DL
|
|
><DT
|
|
><B
|
|
>Table of Contents</B
|
|
></DT
|
|
><DT
|
|
>1. <A
|
|
HREF="#intro"
|
|
>Introduction</A
|
|
></DT
|
|
><DD
|
|
><DL
|
|
><DT
|
|
>1.1. <A
|
|
HREF="#copyright"
|
|
>Copyright and License</A
|
|
></DT
|
|
><DT
|
|
>1.2. <A
|
|
HREF="#disclaimer"
|
|
>Disclaimer</A
|
|
></DT
|
|
><DT
|
|
>1.3. <A
|
|
HREF="#credits"
|
|
>Credits / Contributors</A
|
|
></DT
|
|
><DT
|
|
>1.4. <A
|
|
HREF="#feedback"
|
|
>Feedback</A
|
|
></DT
|
|
><DT
|
|
>1.5. <A
|
|
HREF="#AEN85"
|
|
>Terms Used in this Document</A
|
|
></DT
|
|
></DL
|
|
></DD
|
|
><DT
|
|
>2. <A
|
|
HREF="#theproblem"
|
|
>The Problem</A
|
|
></DT
|
|
><DD
|
|
><DL
|
|
><DT
|
|
>2.1. <A
|
|
HREF="#mangling"
|
|
>Name Mangling</A
|
|
></DT
|
|
><DT
|
|
>2.2. <A
|
|
HREF="#AEN131"
|
|
>Classes</A
|
|
></DT
|
|
></DL
|
|
></DD
|
|
><DT
|
|
>3. <A
|
|
HREF="#thesolution"
|
|
>The Solution</A
|
|
></DT
|
|
><DD
|
|
><DL
|
|
><DT
|
|
>3.1. <A
|
|
HREF="#externC"
|
|
><TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
></A
|
|
></DT
|
|
><DT
|
|
>3.2. <A
|
|
HREF="#loadingfunctions"
|
|
>Loading Functions</A
|
|
></DT
|
|
><DT
|
|
>3.3. <A
|
|
HREF="#loadingclasses"
|
|
>Loading Classes</A
|
|
></DT
|
|
></DL
|
|
></DD
|
|
><DT
|
|
>4. <A
|
|
HREF="#faq"
|
|
>Frequently Asked Questions</A
|
|
></DT
|
|
><DT
|
|
>5. <A
|
|
HREF="#seealso"
|
|
>See Also</A
|
|
></DT
|
|
><DT
|
|
><A
|
|
HREF="#AEN295"
|
|
>Bibliography</A
|
|
></DT
|
|
></DL
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><H1
|
|
CLASS="section"
|
|
><A
|
|
NAME="intro"
|
|
></A
|
|
>1. Introduction</H1
|
|
><P
|
|
> A question which frequently arises among Unix C++ programmers is
|
|
how to load C++ functions and classes dynamically using the
|
|
<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API.
|
|
</P
|
|
><P
|
|
>In fact, that is not always simple and needs some
|
|
explanation. That's what this mini HOWTO does.</P
|
|
><P
|
|
>An average understanding of the <SPAN
|
|
CLASS="systemitem"
|
|
>C</SPAN
|
|
>
|
|
and <SPAN
|
|
CLASS="systemitem"
|
|
>C++</SPAN
|
|
> programming language and of the
|
|
<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API is necessary to understand this
|
|
document.</P
|
|
><P
|
|
>This HOWTO's master location is <A
|
|
HREF="http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/"
|
|
TARGET="_top"
|
|
>http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/</A
|
|
>.</P
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="copyright"
|
|
></A
|
|
>1.1. Copyright and License</H2
|
|
><P
|
|
> This document, <EM
|
|
>C++ dlopen mini HOWTO</EM
|
|
>, is
|
|
copyrighted (c) 2002 by <EM
|
|
>Aaron Isotton</EM
|
|
>.
|
|
Permission is granted to copy, distribute and/or modify this
|
|
document under the terms of the GNU Free Documentation
|
|
License, Version 1.1 or any later version published by the
|
|
Free Software Foundation; with no Invariant Sections, with no
|
|
Front-Cover Texts, and with no Back-Cover Texts.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="disclaimer"
|
|
></A
|
|
>1.2. Disclaimer</H2
|
|
><P
|
|
> 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.
|
|
</P
|
|
><P
|
|
> 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.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="credits"
|
|
></A
|
|
>1.3. Credits / Contributors</H2
|
|
><P
|
|
> In this document, I have the pleasure of acknowledging (in
|
|
alphabetic order):
|
|
</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Joy Y Goodreau <TT
|
|
CLASS="email"
|
|
><<A
|
|
HREF="mailto:joyg (at) us.ibm.com"
|
|
>joyg (at) us.ibm.com</A
|
|
>></TT
|
|
> for
|
|
her editing.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>D. Stimitis <TT
|
|
CLASS="email"
|
|
><<A
|
|
HREF="mailto:stimitis (at) idcomm.com"
|
|
>stimitis (at) idcomm.com</A
|
|
>></TT
|
|
>
|
|
for pointing out a few issues with the formatting and the
|
|
name mangling, as well as pointing out a few subtleties of
|
|
<TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
>.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="feedback"
|
|
></A
|
|
>1.4. Feedback</H2
|
|
><P
|
|
> Feedback is most certainly welcome for this document. Send
|
|
your additions, comments and criticisms to the following email
|
|
address: <TT
|
|
CLASS="email"
|
|
><<A
|
|
HREF="mailto:aaron@isotton.com"
|
|
>aaron@isotton.com</A
|
|
>></TT
|
|
>.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="AEN85"
|
|
></A
|
|
>1.5. Terms Used in this Document</H2
|
|
><P
|
|
></P
|
|
><DIV
|
|
CLASS="variablelist"
|
|
><DL
|
|
><DT
|
|
><TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API</DT
|
|
><DD
|
|
><P
|
|
>The <TT
|
|
CLASS="function"
|
|
>dlclose</TT
|
|
>,
|
|
<TT
|
|
CLASS="function"
|
|
>dlerror</TT
|
|
>,
|
|
<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> and
|
|
<TT
|
|
CLASS="function"
|
|
>dlsym</TT
|
|
> functions as described in the
|
|
<TT
|
|
CLASS="literal"
|
|
>dlopen(3)</TT
|
|
> man page.</P
|
|
><P
|
|
>Notice that we use
|
|
<SPAN
|
|
CLASS="QUOTE"
|
|
>"<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>"</SPAN
|
|
> to refer to
|
|
the individual <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>
|
|
<EM
|
|
>function</EM
|
|
>, and
|
|
<SPAN
|
|
CLASS="QUOTE"
|
|
>"<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API"</SPAN
|
|
> to refer
|
|
to the <EM
|
|
>entire API</EM
|
|
>.</P
|
|
></DD
|
|
></DL
|
|
></DIV
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H1
|
|
CLASS="section"
|
|
><A
|
|
NAME="theproblem"
|
|
></A
|
|
>2. The Problem</H1
|
|
><P
|
|
>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.</P
|
|
><P
|
|
>In the C language, loading a library is very simple (calling
|
|
<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>, <TT
|
|
CLASS="function"
|
|
>dlsym</TT
|
|
> and
|
|
<TT
|
|
CLASS="function"
|
|
>dlclose</TT
|
|
> is enough), with C++ this is a bit
|
|
more complicated. The difficulties of loading a C++ library
|
|
dynamically are partially due to <A
|
|
HREF="#mangling"
|
|
>name
|
|
mangling</A
|
|
>, and partially due to the fact that the
|
|
<TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API was written with C in mind, thus
|
|
not offering a suitable way to load classes.</P
|
|
><P
|
|
>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.</P
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="mangling"
|
|
></A
|
|
>2.1. Name Mangling</H2
|
|
><P
|
|
>In every C++ program (or library, or object file), all
|
|
non-static functions are represented in the binary file as
|
|
<EM
|
|
>symbols</EM
|
|
>. These symbols are special text
|
|
strings that uniquely identify a function in the program,
|
|
library, or object file.</P
|
|
><P
|
|
>In C, the symbol name is the same as the function name:
|
|
the symbol of <TT
|
|
CLASS="function"
|
|
>strcpy</TT
|
|
> will be
|
|
<TT
|
|
CLASS="computeroutput"
|
|
>strcpy</TT
|
|
>, and so on. This is
|
|
possible because in C no two non-static functions can have the
|
|
same name.</P
|
|
><P
|
|
>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 <EM
|
|
>name mangling</EM
|
|
>, 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 <TT
|
|
CLASS="function"
|
|
>foo</TT
|
|
> might look like
|
|
<TT
|
|
CLASS="computeroutput"
|
|
>foo@4%6^</TT
|
|
>, for example. Or it
|
|
might not even contain the word <SPAN
|
|
CLASS="QUOTE"
|
|
>"foo"</SPAN
|
|
>.</P
|
|
><P
|
|
> One of the problems with name mangling is that the C++
|
|
standard (currently [<SPAN
|
|
CLASS="citation"
|
|
>ISO14882</SPAN
|
|
>]) 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 <TT
|
|
CLASS="function"
|
|
>dlsym</TT
|
|
>), this would most
|
|
probably work with your compiler only, and might already be
|
|
broken with the next version.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="AEN131"
|
|
></A
|
|
>2.2. Classes</H2
|
|
><P
|
|
>Another problem with the <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API
|
|
is the fact that it only supports loading
|
|
<EM
|
|
>functions</EM
|
|
>. 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.</P
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H1
|
|
CLASS="section"
|
|
><A
|
|
NAME="thesolution"
|
|
></A
|
|
>3. The Solution</H1
|
|
><DIV
|
|
CLASS="section"
|
|
><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="externC"
|
|
></A
|
|
>3.1. <TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
></H2
|
|
><P
|
|
>C++ has a special keyword to declare a function with C
|
|
bindings: <TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
>. A function declared
|
|
as <TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
> uses the function name as
|
|
symbol name, just as a C function. For that reason, only
|
|
non-member functions can be declared as <TT
|
|
CLASS="literal"
|
|
>extern
|
|
"C"</TT
|
|
>, and they cannot be overloaded.</P
|
|
><P
|
|
>Although there are severe limitations, <TT
|
|
CLASS="literal"
|
|
>extern
|
|
"C"</TT
|
|
> functions are very useful because they can be
|
|
dynamically loaded using <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> just like
|
|
a C function.</P
|
|
><P
|
|
>This does <EM
|
|
>not</EM
|
|
> mean that functions
|
|
qualified as <TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
> cannot contain C++
|
|
code. Such a function is a full-featured C++ function which
|
|
can use C++ features and take any type of argument.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="loadingfunctions"
|
|
></A
|
|
>3.2. Loading Functions</H2
|
|
><P
|
|
>In C++ functions are loaded just like in C, with
|
|
<TT
|
|
CLASS="function"
|
|
>dlsym</TT
|
|
>. The functions you want to load
|
|
must be qualified as <TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
> to avoid
|
|
the symbol name being mangled.</P
|
|
><DIV
|
|
CLASS="example"
|
|
><A
|
|
NAME="AEN156"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 1. Loading a Function</B
|
|
></P
|
|
><P
|
|
>main.cpp:</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>#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);
|
|
}
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
>hello.cpp:</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>#include <iostream>
|
|
|
|
extern "C" void hello() {
|
|
std::cout << "hello" << '\n';
|
|
}
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>The function <TT
|
|
CLASS="function"
|
|
>hello</TT
|
|
> is defined in
|
|
<TT
|
|
CLASS="filename"
|
|
>hello.cpp</TT
|
|
>as <TT
|
|
CLASS="literal"
|
|
>extern
|
|
"C"</TT
|
|
>; it is loaded in <TT
|
|
CLASS="filename"
|
|
>main.cpp</TT
|
|
>
|
|
with the <TT
|
|
CLASS="function"
|
|
>dlsym</TT
|
|
> call. The function must be
|
|
qualified as <TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
> because otherwise
|
|
we wouldn't know its symbol name.</P
|
|
><DIV
|
|
CLASS="warning"
|
|
><P
|
|
></P
|
|
><TABLE
|
|
CLASS="warning"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
><TR
|
|
><TD
|
|
WIDTH="25"
|
|
ALIGN="CENTER"
|
|
VALIGN="TOP"
|
|
><IMG
|
|
SRC="../images/warning.gif"
|
|
HSPACE="5"
|
|
ALT="Warning"></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
><P
|
|
>There are two different forms of the
|
|
<TT
|
|
CLASS="literal"
|
|
>extern "C"</TT
|
|
> declaration: <TT
|
|
CLASS="literal"
|
|
>extern
|
|
"C"</TT
|
|
> as used above, and <TT
|
|
CLASS="literal"
|
|
>extern "C" {
|
|
… }</TT
|
|
> 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:
|
|
|
|
<DIV
|
|
CLASS="informalexample"
|
|
><A
|
|
NAME="AEN174"
|
|
></A
|
|
><P
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>extern "C" int foo;
|
|
extern "C" void bar();
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
></P
|
|
></DIV
|
|
>
|
|
and
|
|
<DIV
|
|
CLASS="informalexample"
|
|
><A
|
|
NAME="AEN176"
|
|
></A
|
|
><P
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>extern "C" {
|
|
extern int foo;
|
|
extern void bar();
|
|
}</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
></P
|
|
></DIV
|
|
>
|
|
|
|
As there is no difference between an
|
|
<TT
|
|
CLASS="literal"
|
|
>extern</TT
|
|
> and a
|
|
non-<TT
|
|
CLASS="literal"
|
|
>extern</TT
|
|
> <EM
|
|
>function</EM
|
|
>
|
|
declaration, this is no problem as long as you are not
|
|
declaring any variables. If you declare
|
|
<EM
|
|
>variables</EM
|
|
>, keep in mind that
|
|
|
|
<DIV
|
|
CLASS="informalexample"
|
|
><A
|
|
NAME="AEN182"
|
|
></A
|
|
><P
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>extern "C" int foo;</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
></P
|
|
></DIV
|
|
>
|
|
and
|
|
<DIV
|
|
CLASS="informalexample"
|
|
><A
|
|
NAME="AEN184"
|
|
></A
|
|
><P
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>extern "C" {
|
|
int foo;
|
|
}</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
></P
|
|
></DIV
|
|
>
|
|
|
|
are <EM
|
|
>not</EM
|
|
> the same thing.</P
|
|
><P
|
|
>For further clarifications, refer to
|
|
[<SPAN
|
|
CLASS="citation"
|
|
>ISO14882</SPAN
|
|
>], 7.5, with special attention
|
|
to paragraph 7, or to [<SPAN
|
|
CLASS="citation"
|
|
>STR2000</SPAN
|
|
>],
|
|
paragraph 9.2.4.</P
|
|
><P
|
|
>Before doing fancy things with extern variables, peruse
|
|
the documents listed in the <A
|
|
HREF="#seealso"
|
|
>see
|
|
also</A
|
|
> section.</P
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H2
|
|
CLASS="section"
|
|
><A
|
|
NAME="loadingclasses"
|
|
></A
|
|
>3.3. Loading Classes</H2
|
|
><P
|
|
>Loading classes is a bit more difficult because we need
|
|
an <EM
|
|
>instance</EM
|
|
> of a class, not just a
|
|
pointer to a function.</P
|
|
><P
|
|
>We cannot create the instance of the class using
|
|
<TT
|
|
CLASS="literal"
|
|
>new</TT
|
|
> because the class is not defined in the
|
|
executable, and because (under some circumstances) we don't
|
|
even know its name.</P
|
|
><P
|
|
>The solution is achieved through polymorphism. We define a
|
|
base, <EM
|
|
>interface</EM
|
|
> class with virtual
|
|
members <EM
|
|
>in the executable</EM
|
|
>, and a derived,
|
|
<EM
|
|
>implementation</EM
|
|
> class <EM
|
|
>in the
|
|
module</EM
|
|
>. Generally the interface class is
|
|
abstract (a class is abstract if it has pure virtual
|
|
functions).</P
|
|
><P
|
|
>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.</P
|
|
><P
|
|
>Next, while still in the module, we define two additional helper
|
|
functions, known as <EM
|
|
>class factory
|
|
functions</EM
|
|
>. 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 <TT
|
|
CLASS="literal"
|
|
>extern
|
|
"C"</TT
|
|
>.</P
|
|
><P
|
|
>To use the class from the module, load the two factory
|
|
functions using <TT
|
|
CLASS="function"
|
|
>dlsym</TT
|
|
> just <A
|
|
HREF="#loadingfunctions"
|
|
>as we loaded the the hello
|
|
function</A
|
|
>; then, we can create and destroy as many
|
|
instances as we wish.</P
|
|
><DIV
|
|
CLASS="example"
|
|
><A
|
|
NAME="AEN210"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 2. Loading a Class</B
|
|
></P
|
|
><P
|
|
>Here we use a generic <TT
|
|
CLASS="classname"
|
|
>polygon</TT
|
|
>
|
|
class as interface and the derived class
|
|
<TT
|
|
CLASS="classname"
|
|
>triangle</TT
|
|
> as implementation.</P
|
|
><P
|
|
>main.cpp:</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>#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);
|
|
}
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
>polygon.hpp:</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>#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
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
>triangle.cpp:</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="programlisting"
|
|
>#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;
|
|
}
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>There are a few things to note when loading classes:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>You must provide <EM
|
|
>both</EM
|
|
> a creation
|
|
and a destruction function; you must
|
|
<EM
|
|
>not</EM
|
|
> destroy the instances using
|
|
<TT
|
|
CLASS="literal"
|
|
>delete</TT
|
|
> from inside the executable, but
|
|
always pass it back to the module. This is due to the fact
|
|
that in C++ the operators <TT
|
|
CLASS="literal"
|
|
>new</TT
|
|
> and
|
|
<TT
|
|
CLASS="literal"
|
|
>delete</TT
|
|
> may be overloaded; this would
|
|
cause a non-matching <TT
|
|
CLASS="literal"
|
|
>new</TT
|
|
> and
|
|
<TT
|
|
CLASS="literal"
|
|
>delete</TT
|
|
> 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.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The destructor of the interface class should be
|
|
virtual in any case. There <EM
|
|
>might</EM
|
|
> 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.</P
|
|
><P
|
|
>If your base class needs no destructor, define an
|
|
empty (and <TT
|
|
CLASS="literal"
|
|
>virtual</TT
|
|
>) one anyway;
|
|
otherwise you <EM
|
|
>will have problems</EM
|
|
>
|
|
sooner or later; I can guarantee you that. You can read
|
|
more about this problem in the comp.lang.c++ FAQ at <A
|
|
HREF="http://www.parashift.com/c++-faq-lite/"
|
|
TARGET="_top"
|
|
>http://www.parashift.com/c++-faq-lite/</A
|
|
>, in
|
|
section 20.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H1
|
|
CLASS="section"
|
|
><A
|
|
NAME="faq"
|
|
></A
|
|
>4. Frequently Asked Questions</H1
|
|
><DIV
|
|
CLASS="qandaset"
|
|
><DL
|
|
><DT
|
|
>4.1. <A
|
|
HREF="#AEN243"
|
|
>I'm using Windows and I can't find the
|
|
<TT
|
|
CLASS="filename"
|
|
>dlfcn.h</TT
|
|
> header file on my PC! What's
|
|
the problem?</A
|
|
></DT
|
|
><DT
|
|
>4.2. <A
|
|
HREF="#AEN257"
|
|
>Is there some kind of <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>-compatible
|
|
wrapper for the Windows <TT
|
|
CLASS="function"
|
|
>LoadLibrary</TT
|
|
>
|
|
API?</A
|
|
></DT
|
|
></DL
|
|
><DIV
|
|
CLASS="qandaentry"
|
|
><DIV
|
|
CLASS="question"
|
|
><P
|
|
><A
|
|
NAME="AEN243"
|
|
></A
|
|
><B
|
|
>4.1. </B
|
|
>I'm using Windows and I can't find the
|
|
<TT
|
|
CLASS="filename"
|
|
>dlfcn.h</TT
|
|
> header file on my PC! What's
|
|
the problem?</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="answer"
|
|
><P
|
|
><B
|
|
> </B
|
|
>The problem is, as usual, Windows. There is no
|
|
<TT
|
|
CLASS="filename"
|
|
>dlfcn.h</TT
|
|
> header on Windows,and there is
|
|
no <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> API. There is a similar API
|
|
around the <TT
|
|
CLASS="function"
|
|
>LoadLibrary</TT
|
|
> function, and
|
|
most of what is written here applies to it, too.
|
|
Alternatively, you can use libltdl (included in libtool) to
|
|
<SPAN
|
|
CLASS="QUOTE"
|
|
>"emulate"</SPAN
|
|
> <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> on a
|
|
variety of platforms.</P
|
|
><P
|
|
>You should also read section 4, <SPAN
|
|
CLASS="QUOTE"
|
|
>"Dynamically
|
|
Loaded (DL) Libraries"</SPAN
|
|
>, of the <A
|
|
HREF="http://www.dwheeler.com/program-library"
|
|
TARGET="_top"
|
|
>Program Library
|
|
HOWTO</A
|
|
> for more techniques to load libraries and
|
|
create classes independently of your platform.</P
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="qandaentry"
|
|
><DIV
|
|
CLASS="question"
|
|
><P
|
|
><A
|
|
NAME="AEN257"
|
|
></A
|
|
><B
|
|
>4.2. </B
|
|
>Is there some kind of <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>-compatible
|
|
wrapper for the Windows <TT
|
|
CLASS="function"
|
|
>LoadLibrary</TT
|
|
>
|
|
API?</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="answer"
|
|
><P
|
|
><B
|
|
> </B
|
|
>I don't know of any, and I don't think there'll ever be one
|
|
supporting all of <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>'s options.</P
|
|
><P
|
|
>There are alternatives though: libtltdl (a part of libtool),
|
|
which wraps a variety of different dynamic loading APIs, among
|
|
others <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
> and
|
|
<TT
|
|
CLASS="function"
|
|
>LoadLibrary</TT
|
|
>. Another one is the <A
|
|
HREF="http://developer.gnome.org/doc/API/glib/glib-dynamic-loading-of-modules.html"
|
|
TARGET="_top"
|
|
>Dynamic
|
|
Module Loading functionality of GLib</A
|
|
>. 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.</P
|
|
></DIV
|
|
></DIV
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="section"
|
|
><HR><H1
|
|
CLASS="section"
|
|
><A
|
|
NAME="seealso"
|
|
></A
|
|
>5. See Also</H1
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>The <TT
|
|
CLASS="function"
|
|
>dlopen(3)</TT
|
|
> man page. It explains
|
|
the purpose and the use of the <TT
|
|
CLASS="function"
|
|
>dlopen</TT
|
|
>
|
|
API.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The article <A
|
|
HREF="http://www.linuxjournal.com/article.php?sid=3687"
|
|
TARGET="_top"
|
|
> <I
|
|
CLASS="citetitle"
|
|
>Dynamic Class Loading for C++ on
|
|
Linux</I
|
|
></A
|
|
> by James Norton published on the
|
|
<A
|
|
HREF="http://www.linuxjournal.com/"
|
|
TARGET="_top"
|
|
>Linux
|
|
Journal</A
|
|
>.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Your favorite C++ reference about <TT
|
|
CLASS="literal"
|
|
>extern
|
|
"C"</TT
|
|
>, inheritance, virtual functions,
|
|
<TT
|
|
CLASS="literal"
|
|
>new</TT
|
|
> and <TT
|
|
CLASS="literal"
|
|
>delete</TT
|
|
>. I
|
|
recommend [<SPAN
|
|
CLASS="citation"
|
|
>STR2000</SPAN
|
|
>].</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>[<SPAN
|
|
CLASS="citation"
|
|
>ISO14882</SPAN
|
|
>]</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The <A
|
|
HREF="http://www.dwheeler.com/program-library"
|
|
TARGET="_top"
|
|
>Program Library
|
|
HOWTO</A
|
|
>, which tells you most things you'll ever need
|
|
about static, shared and dynamically loaded libraries and how
|
|
to create them. Highly recommended.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The <A
|
|
HREF="http://tldp.org/HOWTO/GCC-HOWTO/index.html"
|
|
TARGET="_top"
|
|
>Linux GCC
|
|
HOWTO</A
|
|
> to learn more about how to create libraries
|
|
with GCC.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><A
|
|
NAME="AEN295"
|
|
></A
|
|
><HR><H1
|
|
><A
|
|
NAME="AEN295"
|
|
></A
|
|
>Bibliography</H1
|
|
><DIV
|
|
CLASS="bibliomixed"
|
|
><A
|
|
NAME="AEN296"
|
|
></A
|
|
><P
|
|
CLASS="bibliomixed"
|
|
> ISO14482 <I
|
|
>ISO/IEC 14482-1998 — The
|
|
C++ Programming Language</I
|
|
>. Available as
|
|
PDF and as printed book from <A
|
|
HREF="http://webstore.ansi.org/"
|
|
TARGET="_top"
|
|
>http://webstore.ansi.org/</A
|
|
>.
|
|
</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="bibliomixed"
|
|
><A
|
|
NAME="AEN301"
|
|
></A
|
|
><P
|
|
CLASS="bibliomixed"
|
|
> STR2000
|
|
<SPAN
|
|
CLASS="AUTHOR"
|
|
>Bjarne Stroustrup</SPAN
|
|
>
|
|
<I
|
|
>The C++ Programming Language</I
|
|
>, Special
|
|
Edition.
|
|
ISBN 0-201-70073-5.
|
|
Addison-Wesley.
|
|
</P
|
|
></DIV
|
|
></DIV
|
|
>
|
|
|
|
</body>
|
|
</html>
|