Table of Contents

BUILDING AND USING LIBRARIES

 

 

Basic and Types of Libraries

 

What Is a library?
A library is really nothing more than a collection of object files.
Type of libraries in Linux:

 

Type of libraries in Linux:  Static | Shared - Dynamic Linking |  Shared - Dynamic Loading
Type of libraries in Linux: Static | Shared – Dynamic Linking | Shared – Dynamic Loading

 

Static libraries: Once the application developer compiles and then links with the library, the needed elements of the library are integrated into the resulting executable image. From the perspective of the application, the external library is no longer relevant because it’s been combined with the application image.
Shared – Dynamic Linking: You can dynamically link your program with the shared library and have Linux load the library upon execution (unless it’s already in memory).
Shared – Dynamic Loading: With dynamic loading, an application program can itself load a specific library (unless already loaded), and then call a particular function within that library.

 

 

Difference b/w Static and Shared Libraries

Static Library Shared Library
Static libraries can be beneficial in small programs where minimal functionality is needed.

With a static library, every running program has its own copy of the library.

For programs that require multiple libraries, shared libraries can reduce the memory footprint of the program (both on disk and in memory at run time).

This is because multiple programs can use a shared library simultaneously. Therefore, only one copy of the library is needed in memory at a time.

 

Difference b/w Static and Shared Libraries
Difference b/w Static and Shared Libraries

 

 

 

Sample project Roadmap to implement Static and Shared libraries

 

Sample project Roadmap to implement Static and Shared libraries
Sample project Roadmap to implement Static and Shared libraries

 

 

Steps to Build a static library in Linux

Building Static Library (.a)
$ gcc -c -Wall add.c

$ gcc -c -Wall sub.c

 

We specify the -c option to tell gcc to compile only (don’t link) and also to turn on all warnings. This will generate add.o and sub.o

 

$ ar -cru libmycalc.a add.o sub.o

 

  ar command to build our library (libmycalc.a).

The c option specifies to create the static library (unless it already exists, in which case the option is ignored).

The r option tells ar to replace existing objects in the static library (if they already exist).

The u option is a safety option to specify that objects are replaced in the archive only if the objects to be inserted are newer than existing objects in the archive (of the same name).

We now have a new file called libmycalc.a, which is our static library containing two objects: add.o and sub.o. Let’s now look at how we can build our application using this static library.

 

$ gcc main.c   -L.  -lmycalc  -o  main

$  ./main

 

 The -L. option tells gcc that libraries can be found in the current subdirectory (. represents the directory). The -L option identifies the library to use. When the -L option is used, it automatically surrounds the name specified with lib and .a . Therefore, if the user had specified

-lmycalc, gcc would look for a library called libmycalc.a.

 

 

Building Static Library (.a)
• We can inspect a static library to see what’s contained within it by using the -t option:

 $ ar -t libmycalc.a

 

    add.o

    sub.o

If desired, we can also remove objects from a static library. This is done using the -d option.

   $ ar -d libmycalc.a sub.o

   $ ar -t libmycalc.a

 

   add.o 

 It’s important to note that ar won’t actually show a failure for a delete. To see an error   message, if the delete fails, add a -v option.

  $ ar -d libmycalc.a  sub.o

  $ ar -dv libmycalc.a subo

 

  No member named ‘sub.o

Rather than remove the object from the static library, we can extract it using the -x option.

 

 $ ar -xv libcalc.a  sub.o

 

    x – initapi.o

 

 $ ls

 

     sub.o libmycalc.a

 

 $ ar -t libmycalc.a

 

    add.o sub.o

The extract option doesn’t actually remove the object, it only copies it externally to the archive. The delete (-d) option must be used to remove it outright from the static library.

 

 

 

Important Options for the ar Utility

Important Options for the ar Utility
Option Name Example
-d Delete ar -d <archive> <objects>
-r Replace ar -r <archive> <objects>
-t Table list ar -t <archive>
-x Extract ar -x <archive> <objects>
-v Verbose ar -v
-c Create ar -c <archive>
-ru Update object ar -ru <archive> <objects>

 

 

 

Steps to Build Shared – Dynamic linking Library

Building Shared – Dynamic linking Library
  • First build a shared library using our add.o and sub.o objects.
  • Since the library and application are not tied together as they are in a static library, the resulting library can’t assume anything about the binding application.
  • In addressing, references must be relative.
  • The loader automatically resolves all relative addresses as the shared library is loaded.
  • To build our source files for position-independence, we use the PIC option of gcc:
 

  $ gcc -fPIC -c add.c

  $ gcc -fPIC -c sub.c

 

• This results in two new object files containing position-independent code.

  We can create a shared library of these using gcc and the -shared flag.

  

$ gcc -shared add.o sub.o -o libmycalc.so

 

  •  Note that we use the .so suffix to identify that the file is a shared library (shared object).
  • To build our application using the new shared object, we link the elements back together as we  did with the static library:
  $ gcc main.c -L. -lmycalc -o main

 

  •  We can tell that our new image is dependent upon our shared library by using the ldd command.
   $ ldd test

 

libmycalc.so => not found

libc.so.6 => /lib/tls/libc.so.6 (0x42000000)

/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

 

 

 

Building Shared – Dynamic linked Library
•  The standard C library is shown (libc.so.6)

•  The dynamic linker/loader (ld-linux.so.2)

•  Note that our libmycalc.so file is shown as not found.

•  It’s present in the current subdirectory with our application, but it must be explicitly specified to GNU/Linux through the LD_LIBRARY_PATH environment variable.

 

$ export LD_LIBRARY_PATH=./

 $ ldd test

 

libmycalc.so => ./libmycalc.so (0x40017000)

libc.so.6 => /lib/tls/libc.so.6 (0x42000000)

/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

If we had tried to execute our application without exporting LD_LIBRARY_PATH=./ , a reasonable error message would have resulted, telling us that the shared library could not be found:

$ ./test

 

./test: error while loading shared libraries: libmycalc.so:

cannot find shared object file: No such file or directory.

 

 

 

Steps to Build Shared – Dynamic loaded Library

Building Shared – Dynamic loaded Library
•The final type of library that we’ll explore is the dynamically loaded (and linked) library.

• This library can be loaded at any time during the execution of an application, unlike a shared object that is loaded immediately upon application start-up.

 

 

 $ gcc -fPIC -c add.c

 $ gcc -fPIC -c sub.c

 $ gcc -shared add.o sub.o -o libmycalc.so

 $ su –

  <provide your root password>

 $ cp libmycalc.so /usr/local/lib

 

 Note: In order to copy our library to /usr/local/lib, we must first gain root privileges. To do so we use the su command to create a login shell from the root user.
 Now that we have our shared library re-created, how do we access this in a dynamic fashion from our test application?

  The answer is that we must modify our test application to change the way that we access the API.

 

 

Building Shared – Dynamic loaded Library
The dynamically loaded library API is very simple and are declared in <dlfcn.h>

  • void *dlopen( const char *filename, int flag );
  •  const char *dlerror( void );
  •  void *dlsym( void *handle, char *symbol );
  • int dlclose( void *handle );

 

 

#include<stdio.h>

#include<stdlib.h>

#include<dlfcn.h>

#include"calc.h"

void main()

 {

   int a,b,result;

   void *handle;

   char *err;

   int (*add_d)(int,int);

   int (*sub_d)(int,int);

 

    /* Open a handle to the dynamic library */

   handle=dlopen("/usr/local/lib/libmycalc.so",RTLD_LAZY);

   if(handle==(void *)0)

    {

      fputs(dlerror(),stderr);

      exit(-1);

    }

   

  /*Check access to add() function*/

    add_d= dlsym(handle,"add");

    err = dlerror();

    if(err!=NULL)

    {   fputs(err, stderr);

        exit(-1);

    }


 /*Check access to sub() function*/
    sub_d= dlsym(handle,"sub");
    err = dlerror();
    if(err!=NULL)
    {   fputs(err, stderr);
        exit(-1);
    }
    
     // Call dynamic add function

    printf("Enter 2 numbers\n");
    scanf("%d %d",&a,&b);
    result= (*add_d)(a,b);
    printf("\n Result after add = %d",result);  
   // Call dynamic sub function

    printf("\nEnter 2 numbers\n");
    scanf("%d %d",&a,&b);
    result= (*sub_d)(a,b);
    printf("\n Result after add = %d",result);  
   
   // Close our handle to the dynamic library
     dlclose(handle);

   }

 

  • The first step in using a dynamic library is opening it with dlopen
  •   We specify the library we need to use (/usr/local/lib/libmycalc.so) and also a single flag.
  • Of the two flags that are possible (RTLD_LAZY and RTLD_NOW), we specify RTLD_LAZY to resolve references as we go, rather than immediately upon loading the library, which would be the case with RTLD_NOW.
  • The function dlopen returns an opaque handle representing the opened library.
  •   Note that if an error occurs, we can use the dlerror function to provide an error string suitable for emitting to stdout or stderr.
  •   The API function dlsym searches our shared library for the function defined  (“add”)
  •  Upon locating it, a (void *) pointer is returned and stored in a local function pointer. 
  •   And if an error string was returned, we emit it and exit the application.
  • Similarly the API function dlsym searches our shared library for the function defined (“sub”)
  • Actual calling of add function using local function pointer add_d
  • Actual calling of add function using local function pointer sub_d
  • Our last step in the main application is to close out the library. This is done with the dlclose API function .
  • If the API finds that there are no other users of the shared library, then it is unloaded.

 

 

 

Supporting Utilities : file, size, nm, objdump, ranlib

Utilities : file , size, nm
 fileThe file utility tests the file argument for the purposes of identifying what it is.

 

$ file /usr/local/lib/libmycalc.so

 

   /usr/local/lib/libmyrand.so: ELF 32-bit LSB shared object,

Intel 80386, version 1 (SYSV), not stripped $

 So, using file utility, we can see that our shared library is a 32-bit ELF object for the Intel 80386 processor family. It has been defined as “not stripped,” which simply means that debugging information is present.

size: The size command provides us with a very simple way to understand the text, data, and bss  section sizes for an object.

 

  $ size /usr/local/lib/libmycalc.so

 

     text   data   bss   dec   hex   filename

     2013  264    4     2281 8e9   /usr/local/lib/libmycalc.so

 nm : This commands permits us to look at the symbols that are available within a given object file

 

 $ nm -n /usr/local/lib/libmycalc.so | grep " T "

 

we use nm to print the symbols within the shared library, but then only emit those with the tag ” T ” to stdout (those symbols that are part of the .text section, or code segments). We also use the -n option to sort the output numerically by address, rather than the default, which is alphabetically by symbol name. This gives us relative address information within the library; if we wanted to know the specific sizes of these .text sections, we could use the -S option.

 

 

Utilities: objdump, ranlib
objdump: The objdump utility is similar to nm in that it provides the ability to dig in and inspect the contents of an object.

 

$ objdump -disassemble -S /usr/local/lib/libmycalc.so

 

• -disassemble (to disassemble to the native instruction set)

•  -S to output interspersed source code

 

ranlib : The ranlib utility is one of the most important utilities when creating static libraries.

  This utility creates an index of the contents of the library and stores it in the library file itself.

• When this index is present in the library, the linking stage of building an image can be sped up considerably.

• Therefore, the ranlib utility should be performed whenever a new static library is created.

  $ ranlib libmycalc.a

 

  Note that the same thing can be performed using the ar command with the -s option, as:

 

$ ar -s libmycalc.a