Static and Dynamic Libraries

Why libraries are used ?
 
"Shared components" or "archive libraries", groups together multiple compiled object code files into a single file known as a library. 

Typically C functions/C++ classes and methods which can be shared by more than one application are broken out of the application's source code, compiled and bundled into a library. The C standard libraries and C++ STL are examples of shared components which can be linked with your code. 

What are benefits of using shared libraries ?
  • The benefit is that each and every object file need not be stated when linking because the developer can reference the individual library. This simplifies the multiple use and sharing of software components between applications. 
  • It also allows application vendors a way to simply release an API to interface with an application. 
  • Components which are large can be created for dynamic use, thus the library remain separate from the executable reducing it's size and thus disk space used. The library components are then called by various applications for use when needed.

Static and Dynamic Libraries

When a C program is compiled, the compiler generates object code. After generating the object code, the compiler also invokes linker. One of the main tasks for linker is to make code of library functions (eg printf(), scanf(), sqrt(), ..etc) available to your program. A linker can accomplish this task in two ways, by copying the code of library function to your object code, or by making some arrangements so that the complete code of library functions is not copied, but made available at run-time.

Static Linking and Static Libraries is the result of the linker making copy of all used library functions to the executable file. Static Linking creates larger binary files, and need more space on disk and main memory. Examples of static libraries (libraries which are statically linked) are, .a files in Linux and .lib files in Windows. 
Steps to create a static library Let us create and use a Static Library in UNIX or UNIX like OS.

1. Create a C file that contains functions in your library.
[root@staticLibrary.c]# vim lib_mylib.c
/* lib_mylib.c */
#include <stdio.h>

void fun(void)
{
  printf("fun() called from a static library");
}

We have created only one file for simplicity. We can also create multiple files in a library.

2. Create a header file for the library 
[root@staticLibrary.c]# vim lib_mylib.h

/* lib_mylib.h */ 
void fun(void);

3. Compile library files.
[root@staticLibrary.c]# gcc -c lib_mylib.c -o lib_mylib.o
[root@staticLibrary.c]# ls
lib_mylib.c  lib_mylib.h  lib_mylib.o



4. Create static library. This step is to bundle multiple object files in one static library (see ar for details). The output of this step is static library.
[root@staticLibrary.c]# ar rcs lib_mylib.a lib_mylib.o


5. Now our static library is ready to use. 
[root@staticLibrary.c]# ls
lib_mylib.a  lib_mylib.c  lib_mylib.h  lib_mylib.o


6. At this point we could just copy lib_mylib.a somewhere else to use it. For demo purposes, let us keep the library in the current directory.

Let us create a driver program that uses above created static library.
1. Create a C file with main function


/* mainprog.c  */
#include "lib_mylib.h"
int main()
{
  fun();

  return 0;
}


2. Compile the mainprog : 
[root@staticLibrary.c]# gcc -c mainprog.c -o mainprog.o



3. Link the compiled driver program to the static library. Note that -L. is used to tell that the static library is in current folder (See this for details of -L and -l options).

[root@staticLibrary.c]# gcc -o mainprog mainprog.o -L. -l_mylib
 

4. The compiled file is mainprog :
[root@staticLibrary.c]# ls
lib_mylib.a  lib_mylib.c  lib_mylib.h  lib_mylib.o  mainprog  mainprog.c  mainprog.o



5. Execute the compiled file mainprog : 
[root@staticLibrary.c]# ./mainprog
fun() called from a static library


Dynamic linking and Dynamic Libraries Dynamic Linking doesn’t require the code to be copied, it is done by just placing name of the library in the binary file. The actual linking happens when the program is run, when both the binary file and the library are in memory. Examples of Dynamic libraries (libraries which are linked at run-time) are, .so in Linux and .dll in Windows. 

How to generate a shared object: (Dynamically linked object library file.) Note that this is a two step process.
  • Create object code
  • Create library
  • Optional: create default version using a symbolic link.
Library creation example:
1. We have two functions which are being called by main().

[root@dynamicLibrary.c]# vim fun1.c

/* fun1.c */ 
void fun1(int *i)
{
   *i=5;
}


[root@dynamicLibrary.c]# vim fun2.c
/* fun2.c */
 fun2.c
void fun2(int *i)
{
   *i=100;
}


[root@dynamicLibrary.c]# vim prog.c
/* prog.c */
#include <stdio.h>
void fun1(int *);
void fun2(int *);

int main()
{
   int x;
   fun1(&x);
   printf("Value of x=%d\n",x);

   return 0;
}
  

2. Compile all the files together :

gcc -Wall -fPIC -c *.c 
gcc -shared -Wl,-soname,libfun.so.1 -o libfun.so.1.0   *.o 

[root@dynamicLibrary.c]# ls
fun1.c  fun1.o  fun2.c  fun2.o  libfun.so.1.0  prog.c  prog.o


3. Creates the library libfun.so.1.0 and symbolic links to it.

 mv libfun.so.1.0 /opt/lib 
ln -sf /opt/lib/libfun.so.1.0 /opt/lib/libfun.so.1 
ln -sf /opt/lib/libfun.so.1.0 /opt/lib/libfun.so

4. To cascade the linkage:


ln -sf /opt/lib/libfun.so.1.0 /opt/lib/libfun.so.1
ln -sf /opt/lib/libfun.so.1   /opt/lib/libfun.so
   
If you look at the libraries in /lib/ and /usr/lib/ you will find both methodologies present. Linux developers are not consistent. What is important is that the symbolic  links eventually point to an actual library.


Compiler options:

-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 libfun.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 "libfun.so.1.0"
 

Library Links:

The link to /opt/lib/libfun.so allows the naming convention for the compile flag -lfun to work.
The link to /opt/lib/libfun.so.1 allows the run time binding to work. See dependency below.
 

Compile main program and link with shared object library:

Compiling for runtime linking with a dynamically linked libfun.so.1.0: 

gcc -Wall -I/path/to/include-files -L/path/to/libraries prog.c -lfun -o prog
         
Use:
 gcc -Wall -L/opt/lib prog.c -lfun -o prog

[root@dynamicLibrary.c]#  gcc -Wall -L/opt/lib prog.c -lfun -o prog
[root@dynamicLibrary.c]# ls
fun1.c  fun1.o  fun2.c  fun2.o  prog  prog.c  prog.o


Where the name of the library is libfun.so. (This is why you must create the symbolic links or you will get the error "/usr/bin/ld: cannot find -lfun".)
 

The libraries will NOT be included in the executable but will be dynamically linked during runtime execution.

List Dependencies:

The shared library dependencies of the executable can be listed with the command: ldd name-of-executable

Example: ldd prog
[root@dynamicLibrary.c]# ldd prog
        linux-gate.so.1 =>  (0xffffe000)
        libfun.so.1 => not found
        libc.so.6 => /lib/tls/libc.so.6 (0x0031e000)


Add the library path to the environment variable to fix runtime dependency:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib

[root@dynamicLibrary.c]#export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH
[root@dynamicLibrary.c]# ldd prog
        linux-gate.so.1 =>  (0xffffe000)
        libfun.so.1 => /opt/lib/libfun.so.1 (0xb7f05000)
        libc.so.6 => /lib/tls/libc.so.6 (0x0031e000)
        /lib/ld-linux.so.2 (0x00304000)


Output :
[root@dynamicLibrary.c]# ./prog
Value of x=5

No comments:

Post a Comment