1. Background
In Java, the JVM supports dynamic linking of classes (Class.forName (String className)), which is also convenient to use. Dynamic linking is the key to implementing the IOC (inversion of control, inversion, and more image called Dependency injection), which is used to move dependencies between classes into a configuration file. Replaces the dependent class if the frame is not recompiled.
Under Linux, C + + can only implement dynamic links through the DL API for C, and you need to compile the dynamic link library into. So before calling the API for a link. Let's look at how to implement a dynamically linked C + + class. Like the Java implementation IOC, a link class needs to be dependent on an interface to first define the interface parts that the framework needs to rely on:
Class UserInterface {public
:
virtual bool func () = 0;
};
The dynamic link library implementation partially inherits this interface and implements it.
Class Concretinterface:public UserInterface {public
:
virtual bool Func () {
printf ("A implementition of UserInterface ");
}
;
2. DL API
Introduce the DL API section first, these functions need to connect the DL dynamic Library,-LDL:
void *dlopen (const char *filename, int flag);
Used to open. So, and link to return the link after the handle. Flag indicates link flags:
Rtld_lazy: Deferred loading, the first time a symbol is used in. So is then linked. Valid only for function symbols, the variable symbols are loaded immediately.
Rtld_now: After Dlopen returns, all undefined symbols need to be linked, and if the symbol resolution fails, DLOPEN returns a failure.
Rtld_global: Using this flag, the symbols in this library can be used by subsequent dynamic libraries.
Rtld_local: In contrast to Rtld_global, it cannot be used by subsequent dynamic libraries.
Char *dlerror (void);
Returns a DL-related error that returns null if there are no errors from initialization or from the last call to date.
void *dlsym (void *handle, const char *symbol);
Returns the address of a symbol with symbol name symbol, which requires the handle of the dynamic link library returned by Dlopen. You need to use Dlerror to verify that the dlsym is wrong, and that you cannot enter the error by whether the returned pointer is null, because it is normal for the symbolic address to be null.
int dlclose (void *handle);
Reduce the reference count of. So, if the reference count is 0, then. So will be uninstalled.
3. Class Load Implementation
The DL API above shows that only the address of a symbol in a dynamic-link library can be returned, a symbolic function symbol or a variable symbol that cannot be returned directly to a class like java. When we are dynamically linking a class, we actually just need an instance object for that class, so we can implement the connection to the class by returning the function symbol that created the class object. Because in C + +, you can overload the new operator, do some other operations, allocate resources, and so on, call Delete to release the object, will cause a resource leak. So in order to support overloading the new operator, you also need to dispose of the object's functions. The definition is as follows:
typedef BOOL (*user_interface_creator_t) (UserInterface **ui);
typedef void (*user_interface_destroyer_t) (UserInterface *ui);
Two function pointers are defined above, which are the creator and the destruction of the link class. dynamic-link libraries need to implement both functions, so that the framework can create and destroy objects. If the new operation overload is not supported by default, you can remove the destroyer and simplify the interface.
It is also important that because C + + supports mechanisms such as namespaces, classes, and overloads, the naming rules for symbols are different from C. While the DL API is part of C and uses the naming rules for C, you need to use the symbol naming rules for C when implementing both of these functions (that is, C + + functions that need to be dynamically linked). This requires the implementation of extern ' C ', as follows:
extern ' C ' {
bool My_creator (userinterface **ui)
{
if (NULL = = UI) {
printf ("Invalid param");
return false;
}
*ui = new (Std::nothrow) concrectinterface;
return true;
}
void My_destroyer (UserInterface *ui)
{
if (UI!= NULL) {
delete ui;
}}}
;
My_creator and My_destroyer is the implementation of the dynamic link library to the interface, can be called by the function name Dlsym find the corresponding address, complete the creation and destruction of objects. Next, introduce the framework, which is the part of the dynamic link.
#include <dlfcn.h> #include <stdio.h> #include "user_interface.hpp" const char *so_path = "./user_impl.so";
const char *creat_func = "My_creator";
const char *destroy_func = "My_destroyer";
int main () {//load. So void *handle = Dlopen (So_path, Rtld_lazy);
if (NULL = = handle) {printf ("Failed to open%s, error:%s", So_path, Dlerror ());
return 1;
}//Reset errors Dlerror ();
user_interface_creator_t creator = (user_interface_creator_t) dlsym (handle, Creat_func);
Const char* Err = Dlerror ();
if (Err!= NULL) {printf ("Failed to load creator, error:%s", err);
return 1;
}//Reset errors Dlerror ();
user_interface_destroyer_t destroyer = (user_interface_destroyer_t) dlsym (handle, Destroy_func);
Err = Dlerror ();
if (Err!= NULL) {printf ("Failed to load destroyer, error:%s", err);
return 1;
} userinterface *ui; if (!) (
*creator) (&ui)) {printf ("Failed to creat UI");
return 1;
} ui->func (); (*destroyer)
(UI);
Dlclose (handle); }
Note that you need to call Dlerror to clear the error state every time you call the DL API function.
4. Pit
If dynamic-link libraries and executable programs rely on the same library, such as relying on the same log library, you need to be aware when compiling the dynamic link libraries and executable programs. Make sure that the parse for the symbol reference for the library points to the same symbol. Specific practices:
(1) When compiling. So, do not link dependent libraries, references to library symbols are undefined.
(2) The executable program needs to link dependent libraries, and to specify the link option-rdynamic, the global symbol can be used for parsing the symbolic reference of the dynamic-link library.
If the above two points are not achieved, the same symbol reference will be resolved to two symbols, if the symbol depends on a variable symbol (such as the symbol itself is a variable, or a function symbol, but dependent on a variable), then there will be a strange, abnormal phenomenon.
For. So relies on a library, but the executable program is not dependent, then compile. So must link this library, otherwise there will be undefined symbol.
Describes the tools that are used to debug a dynamic-link library, because there are a variety of undefined symbols, so you need to see the symbol information for. So or executable programs, you can use NM, for example, type U or symbol of type T. You can also use c++filt to parse a symbol name into a readable string.