Pages

Wednesday, February 9, 2011

Creating shared libraries

  • Intro
    Shared libraries are libraries that are loaded by programs when they start. To function properly, some conventions must be followed, related to library names and location:
    1. A shared library has a special name called the ``soname'', with the prefix ``lib'', the name of the library, the phrase ``.so'', followed by a period and a version number that is incremented whenever the interface changes (libmyfunctions.so.1)
    2. A fully-qualified soname is simply a symbolic link to the shared library's ``real name''. (libmyfunctions.so.1 -> libmyfunctions.so.1.0.1)
    3. A shared library also has a ``real name'', which is the filename containing the actual library code. The real name adds to the soname a period, a minor number, another period, and the release number. The last period and release number are optional. The minor number and release number support configuration control by letting you know exactly what version(s) of the library are installed. ( libmyfunctions.so.1.0.1 )
  • Creating and testing
    Files used are the same as in the static library example (add.c, mult.c, foo.c, myfunctions.h).
    $ gcc -fPIC -g -c -Wall add.c mult.c
    $ gcc -shared -Wl,-soname,libmyfunctions.so.1 -o libmyfunctions.so.1.0.1 add.o mult.o -lc
    $ ln -sf libmyfunctions.so.1.0.1 libmyfunctions.so
    $ ln -sf libmyfunctions.so.1.0.1 libmyfunctions.so.1
    $ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
    $ gcc -Wall -L. foo.c -lmyfunctions -o foo
    
    More about library placement on filesystem and  LD_LIBRARY_PATH environment variable here.
  • Dynamic loading and un-loading of shared libraries
    Libraries can be loaded and unloaded during the execution of the program, creating a plugin architecture. It's important to understand the linkage and when/how to use extern "C" {...}. The C++ compiler mangles the name of C++ functions, but also the C variable names (info here). To list symbols names use nm utility (nm libmyfunctios.so). The source of the main program, that will be compiled with g++:
    foo.cpp:
    #include <stdio.h>
    #include <stdlib.h>
    #include <dlfcn.h>
    
    int main(int argc, char **argv) 
    {
       void *lib_handle;
       int (*fn)(int, int);
       
       char *error = NULL;
    
     int sum = 0;
    
       /* Load library */
       lib_handle = dlopen("libmyfunctions.so", RTLD_LAZY);
       if (!lib_handle) 
       {
          fprintf(stderr, "dlopen error: %s\n", dlerror());
          exit(1);
       }
    
       /* Load symbol */ 
       *(void **) (&fn) = dlsym(lib_handle, "add");
       /* see dlsym man page for this casting reason */
       if ((error = dlerror()) != NULL)  
       {
          fprintf(stderr, "dlsym error: %s\n", error);
          exit(1);
       }
    
       sum = (*fn)(0x11,0x22);
       printf("Sum: %d\n", sum);
    
       dlclose(lib_handle);
    
       return 0;
    }
    
    To compile and check it:
    $ g++ -rdynamic foo.cpp -ldl
    $ ./a.out
    
    More information on dlsym function and binding parameters used in dlopen(RTLD_LAZY, RTLD_GLOBAL and RTLD_NOW) on the man page.
  • Dynamic library loading on windows
  • Links: