C + + Dlopen Mini HOWTO Chinese version __c++

Source: Internet
Author: User
C + + Dlopen Mini HOWTO Chinese versionC + + Dlopen Mini HOWTO
Author: Aaron Isotton <aaron@isotton.com> 2006-03-16
Translator: Lolita@linuxsir.org 2006-08-05----------------------------------------------------------------------
Summary
How to dynamically load C + + functions and classes using the Dlopen API
----------------------------------------------------------------------


Introduced
How to dynamically load C + + functions and classes using the Dlopen API is a common problem for UNIX C + + programmers. In fact, the situation is occasionally somewhat complicated and requires some explanation. This is the reason to write this mini howto.
Understanding this document is premised on a basic understanding of the Dlopen API in the C + + language.

Terms
Dlopen API
Descriptions of the Dlclose, Dlerror, Dlopen, and DLSYM functions can be found on the Dlopen (3) Man's manual page.
Note that when we use "Dlopen", we refer to the Dlopen function, while using the "Dlopen API" refers to the entire API collection.

Where the problem lies
Sometimes you want to load a library (and use the functions in it) at run time, which often happens when you write a plugin or module architecture for your program.
In C, loading a library is easy (calling Dlopen, Dlsym, and Dlclose is enough), but for C + +, the situation is slightly more complicated. The difficulty in dynamically loading a C + + library is partly because of the name mangling of C + + (Translator Note: It is also translated as "name destruction", I think it is still not translated, and partly because the Dlopen API is implemented in C language, and thus does not provide a suitable way to load classes.
Before you explain how to load a C + + library, it's a good idea to learn more about name mangling. I recommend that you take a look at it, even if you are not interested in it. Because it helps you understand how problems are created and how they can be addressed.

Name mangling
In each C + + program (or library, destination file), all non-static (non-static) functions appear in binary files in the form of "symbol". These symbols are unique strings that distinguish functions from programs, libraries, and target files.
In C, the symbol name is the function name: the symbol name of the strcpy function is "strcpy", and so on. This may be because the names of two non-static functions must be different.
C + + allows overloading (different functions have the same name but different parameters), and there are many features that C does not--such as class, member functions, exception description--almost impossible to directly use the function name symbol. To solve this problem, C + + uses the so-called name mangling. It is the name of the function and some information (such as the number of parameters and size) together, to create grotesque, only the compiler to understand the symbol name. For example, Foo may look like a foo@4%6^ after being mangle, or it might not even include "foo" in the symbol name.
One of the problems is that the C + + standard (currently [ISO14882]) does not define how the name must be mangle, so each compiler carries out the name mangling in its own way. Some compilers even replace mangling algorithms (especially g++ 2.x and 3.x) between different versions. Even if you figure out exactly how your compiler is mangling, you can invoke the function with Dlsym, but it may be limited to the compiler at hand, and you won't be able to work under the next version of the compiler.

Class
Another problem with using the Dlopen API is that it only supports loading functions. But in C + +, you might want to use a class in the library, which requires creating an instance of the class, which is not easy to do.

Solution

extern "C"
C + + has a specific keyword to declare a function with C binding: extern "C". Functions declared with extern "C" will use the name of the function famous symbol, just like the C function. Therefore, only non-member functions can be declared as extern "C" and cannot be overloaded. Despite the limitations, the extern "C" function is useful because they can be dlopen dynamically like C functions. By using the extern "C" qualifier, it does not mean that C + + code is not available in the function, but instead it is still a complete C + + function that can use any of the C + + attributes and various types of parameters.

Load Function
In C + +, functions are loaded with Dlsym, as in C. However, the function is declared with an extern "C" qualifier to prevent its symbol name from being mangle.

Example 1. Load function
Code:
//----------
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) ();

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:
//----------
#include <iostream>

extern "C" void Hello ()
{
Std::cout << "Hello" << ' \ n ';
In Hello.cpp, the function hello is defined as extern "C". It is called in the main.cpp by the Dlsym. The function must be qualified with extern "C", otherwise we have no way of knowing its symbolic name.

Warning:
There are two types of declarations for extern "C": the inline (inline) Form of extern "C" used in the example above, and the extern "C" {...} with curly braces. This. The first inline form declaration contains two levels of meaning: external links (extern linkage) and C-language links (language linkage), while the second affects only language links.

The following two forms of declaration are equivalent:
Code: extern "C" int foo;
extern "C" void Bar (); And
Code: extern "C"
{
extern int foo;
extern void Bar ();
For functions, there is no difference between extern and non-extern function declarations, but they are different for variables. If you declare a variable, keep in mind:
Code: extern "C" int foo; And
Code: extern "C"
{
int foo;
It's a different thing. In short, the former is a declaration; the latter is not just a declaration, it can be a definition.

   Load Class
Loading classes are a bit difficult because we need an instance of the class, not just a function pointer. We cannot create an instance of a class through new, because the class is not defined in the executable file, and (sometimes) we don't even know its name.
The solution is: use polymorphism. We define an interface base class with virtual member functions in the executable file, and define the derived implementation class in the module. Typically, an interface class is abstract (if a class contains a virtual function, it is abstract).
Because dynamic load classes are often used to implement plug-ins, this means that a well-defined interface must be provided--we will define an interface class and a derived implementation class.
Next, in the module, we will define two additional helper functions that are known as "class factory functions" (Translator note: or object factory function). One of the functions creates a class instance and returns its pointer; Another function is used to destroy the pointer. Both functions qualify as extern "C".
To use the classes in the module, we loaded the functions like the Hello function in Example 1, and then we were able to create and destroy the instances as we dlsym.

Example 2. Load Class
We use a general polygon class as an interface, while inheriting its triangle class (translator Note: Positive triangle Class) as the implementation.
Code://----------
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;
}

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:
//----------
#ifndef POLYGON_HPP
#define POLYGON_HPP

Class polygon
{
Protected
Double side_length_;

Public
Polygon ()
: Side_length_ (0) {}

Virtual ~polygon () {}

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 to new Triangle;
}

extern "C" void Destroy (polygon* p)
{
Delete p;
There are some notable areas for loading classes:
You must (Translator Note: In the module or shared library) simultaneously provides a creation function and a destruction function, and cannot use delete inside the execution file to destroy the instance, can only pass the instance pointer to the module's destruction function processing. This is because in C + +, the new operator can be overloaded; this easily leads to new-delete mismatched calls, resulting in inexplicable memory leaks and segment errors. This is also the case when linking modules and executables with different standard libraries.
The destructor of an interface class must in any case be a virtual function (virtual). Because even if the error may be very small, almost unfounded, but still not worth the risk, anyway, the extra cost is insignificant. If the base class does not need a destructor, define an empty (but must-be-virtual) destructor, or you will have a problem sooner or later, I assure you.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.