Powered By Blogger

Wednesday, June 6, 2018

Static and dynamic libraries

Linux Library Types:

There are two Linux C/C++ library types which can be created:
  1. Static libraries (.a): Library of object code which is linked with, and becomes part of the application.
  2. Dynamically linked shared object libraries (.so): There is only one form of this library but it can be used in two ways.
    1. Dynamically linked at run time. The libraries must be available during compile/link phase. The shared objects are not included into the executable component but are tied to the execution.
    2. Dynamically loaded/unloaded and linked during execution (i.e. browser plug-in) using the dynamic linking loader system functions.

Library naming conventions:

Libraries are typically named with the prefix "lib". This is true for all the C standard libraries. When linking, the command line reference to the library will not contain the library prefix or suffix.

Consider the following compile and link command: gcc src-file.c -lm -lpthread 

The libraries referenced in this example for inclusion during linking are the math library ("m") and the thread library ("pthread"). They are found in /usr/lib/libm.a and /usr/lib/libpthread.a.

Static Libraries: (.a)
How to generate a static library (object code archive file):
  • Compile: cc -Wall -c ctest1.c ctest2.c 
    Compiler options:
    • -Wall: include warnings. See man page for warnings specified.
  • Create library "libctest.a": ar -cvq libctest.a ctest1.o ctest2.o
  • List files in library: ar -t libctest.a
  • Linking with the library:
    • cc -o executable-name prog.c libctest.a
    • cc -o executable-name prog.c -L/path/to/library-directory -lctest

Dynamically Linked "Shared Object" Libraries: (.so)

How to generate a shared object: (Dynamically linked object library file.) Note that this is a two step process.
  1. Create object code
  2. Create library
  3. Optional: create default version using a symbolic link.
Library creation example:

    gcc -Wall -fPIC -c *.c
    gcc -shared -Wl,-soname,libctest.so.1 -o libctest.so.1.0   *.o
    mv libctest.so.1.0 /opt/lib
    ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1
    ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.soCompiler 
  • -Wall: include warnings. See man page for warnings specified.
  • -fPIC: Compiler directive to output position independent code, a characteristic required by shared libraries. Also see "-fpic".
  • -shared: Produce a shared object which can then be linked with other objects to form an executable.
  • -Wl,options: Pass options to linker. 
    In this example the options to be passed on to the linker are: "-soname libctest.so.1". The name passed with the "-o" option is passed to gcc.
  • Option -o: Output of operation. In this case the name of the shared object to be output will be "libctest.so.1.0"
Library Links:
  • The link to /opt/lib/libctest.so allows the naming convention for the compile flag -lctest to work.
  • The link to /opt/lib/libctest.so.1 allows the run time binding to work. See dependency below.
Compile main program and link with shared object library:

gcc -Wall -L/opt/lib prog.c -lctest -o prog
Library Path:
In order for an executable to find the required libraries to link with during run time, one must configure the system so that the libraries can be found. Methods available: (Do at least one of the following)
  1. Add library directories to be included during dynamic linking to the file /etc/ld.so.conf
    Sample: /etc/ld.so.conf
    /usr/X11R6/lib
    /usr/lib
    ...
    ..
    /usr/lib/sane
    /usr/lib/mysql
    /opt/lib
              
    Add the library path to this file and then execute the command (as root) ldconfig to configure the linker run-time bindings. 
    You can use the "-f file-name" flag to reference another configuration file if you are developing for different environments. 
    See man page for command ldconfig.
    OR
  2. Add specified directory to library cache: (as root) 
    ldconfig -n /opt/lib 
    Where /opt/lib is the directory containing your library libctest.so 
    (When developing and just adding your current directory: ldconfig -n . Link with -L.)
    This will NOT permanently configure the system to include this directory. The information will be lost upon system reboot.
    OR
  3. Specify the environment variable LD_LIBRARY_PATH to point to the directory paths containing the shared object library. This will specify to the run time loader that the library paths will be used during execution to resolve dependencies. 
    (Linux/Solaris: LD_LIBRARY_PATH, SGI: LD_LIBRARYN32_PATH, AIX: LIBPATH, Mac OS X: DYLD_LIBRARY_PATH, HP-UX: SHLIB_PATH)
    Example (bash shell): export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH or add to your ~/.bashrc file:
    ...
    if [ -d /opt/lib ];
    then
       LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH
    fi
    
    ...
    
    export LD_LIBRARY_PATH
          

    This instructs the run time loader to look in the path described by the environment variable LD_LIBRARY_PATH, to resolve shared libraries. This will include the path /opt/lib.
Library paths used should conform to the "Linux Standard Base" directory structure.

Dynamic loading and un-loading of shared libraries using libdl:
01#include <stdio.h>
02#include <dlfcn.h>
03#include "ctest.h"
04 
05int main(int argc, char **argv)
06{
07   void *lib_handle;
08   double (*fn)(int *);
09   int x;
10   char *error;
11 
12   lib_handle = dlopen("/opt/lib/libctest.so", RTLD_LAZY);
13   if (!lib_handle)
14   {
15      fprintf(stderr, "%s\n", dlerror());
16      exit(1);
17   }
18 
19   fn = dlsym(lib_handle, "ctest1");
20   if ((error = dlerror()) != NULL) 
21   {
22      fprintf(stderr, "%s\n", error);
23      exit(1);
24   }
25 
26   (*fn)(&x);
27   printf("Valx=%d\n",x);
28 
29   dlclose(lib_handle);
30   return 0;
31}

gcc -rdynamic -o progdl progdl.c -ldl
Explanation:
  • dlopen("/opt/lib/libctest.so", RTLD_LAZY); 
    Open shared library named "libctest.so". 
    The second argument indicates the binding. See include file dlfcn.h
    Returns NULL if it fails. 
    Options:
    • RTLD_LAZY: If specified, Linux is not concerned about unresolved symbols until they are referenced.
    • RTLD_NOW: All unresolved symbols resolved when dlopen() is called.
    • RTLD_GLOBAL: Make symbol libraries visible.
  • dlsym(lib_handle, "ctest1"); 
    Returns address to the function which has been loaded with the shared library.. 
    Returns NULL if it fails. 
    Note: When using C++ functions, first use nm to find the "mangled" symbol name or use the extern "C" construct to avoid name mangling. 
    i.e. extern "C" void function-name();

No comments:

Post a Comment