By Seedhom at 2009-11-03 04:39
Once you create a set of functions that you like to reuse in multiple programs, you typically build them into a library. The norm in Linux now has moved away from Static libraries (*.a) and more towards Shared Libraries (*.so). Shared libraries can either be linked-in at compile time from a specific location on the system using -l and -L flags or can be loaded dynamically while the program is executing. There are advantages and disadvantages for each of those 2 cases. However, without going into depth about this, let me describe a case where dynamic loading of a shared library is most relevant.
Assume I am writing a server with the purpose to serve applications to users. A typical case is when the user runs a client front-end application from which he makes requests to the server to execute other applications on the server side. The requested applications has to be available to the server in the form of a loadable objects. These loadable objects or shared libraries do not have to be predefined to the server before it starts, nor does the server need to know what they do once they are loaded. All the server needs to know is where these libraries are in its file system and the name of the function the user needs to call.
The example I am going to show here is not as elaborate as an application server, but it will show the technique fully.
The Shared Library
Start with the shared library I want to create with a trivial code:
Let us save this file as a C++ file just for kicks and call it myloadingtest.cpp
int main(int argv, char *argc)
printf("Hey World - I am loaded\n");
To compile the above code as a shared library, we will do this in 2 steps:
- (1) Compile using the -fPIC flag :
This will generate a position-independent code (PIC) so the OS dynamic loader can position it as it sees fit. Here is the compile line
(2) Generate the shared library from the object we just created:[/li] We will need the -shared flag to tell that to the compiler. I am going to name the lib libmyloadingtest.so. Here is the line:
g++ -fPIC -c myloadingtest.cpp
g++ -shared -o libmyloadingtest.so myloadingtest.o
Now we have a shared library with only one entry: main(int, char **) in it.
Now for the loading application (or server)...
Shared Library Loader:
Let me jump right away into the code:
Save the above code as file a C++ file dynamic_libload.cpp
int main(int argc, char *argv)
void *handle; // Pointer to the library location
int (*mymain)(void); // Pointer to point to the function in the lib to execute
char *error; // Pointer to the error that maybe returned by the dlerror() call
// load the shared lib using Run Time Loader lazy mode
handle = dlopen ("./mydynlibs/libmyloadingtest.so", RTLD_LAZY);
printf("This is an error in loading \n");
printf("Library loaded successfully. Finding the function we need ..\n");
// Resolve the function call ..
mymain = (int (*)())dlsym(handle, "main");
if ((error = dlerror()) != NULL)
printf("Error: I did NOT find the symbol 'main' \n");
printf("Success: Symbol 'main' was found. Calling it now ..\n");
mymain(); // Call the function entry in the library
To compile, use this line
That is it!!
g++ -g dynamic_libload.cpp -o dynamic_libload -ldl
Now a couple of points:
There are only 2 calls needed to load a shared library dynamically:
And 2 calls are needed for each function symbol you need to point to:
void *handle = dlopen ("/path/to/lib/mylibname.so", RTLD_LAZY);
Another note to make about the option used in dlopen() call: You can either use RTLD_LAZY or RTLD_NOW. The first is the LAZY option which allows the loader to bind the library IF and only WHEN a function call is made to one of the library functions. The NOW option forces the loader to bind and resolve all the symbols in the shared library before the dlopen() returns. That could be a waste of time if for some reason the program decides not to call any of its functions.
myfunc_ptr = (<type> (*)())dlsym(handle, "function_name");
// if myfunc_ptr turns NULL, then call
error = dlerror()
- Al Sabawi (Seedhom)
Nov. 2, 2009