12 February 2011

How to write a static library in Linux

I am going to illustrate how to write a static library in C for Linux.

requirements: a Linux distribution with GCC installed.

1- First, we need to write the header file of our library:

// complex.h
#ifndef _COMPLEX_H
#define _COMPLEX_H

typedef struct
{
    double real;
    double imaginary;
    
}complex_t;

void add(complex_t *const dest, const complex_t *const src);
static int assert_ptr_not_null(void *);

#endif

2- second, let's write the implementation for this libary:
//complex.c
#include <stdio.h>
#include "complex.h"

void add(complex_t *const dest, const complex_t *const src)
{
    
    if ( !assert_ptr_not_null((void*)dest) || !assert_ptr_not_null((void*)src) )
    {
        fprintf(stderr, "NULL Pointers passed");
        return;
    }
    
    
    dest->real = dest->real + src->real;
    dest->imaginary = dest->imaginary + src->imaginary;
}

static int assert_ptr_not_null(void *ptr)
{
    if (ptr == NULL) return 0;
    return 1;
}

3- let's compile the library (but not link it), use the following command to compile the library:

>cc -c complex.c

-c tell the compiler not to do the linking phase
this command will output a files named "complex.o", and it is the object file for our library

4- static libraries in C are archives that contains object files, so let's archive our object file.
use the following command :

>ar libcomplex.a complex.o
ar: is a regular archiving program found in Linux.
libcomplex.a: is the name of our library, it should start with "lib" and ends by ".a" and in between, you can name it as you like.
complex.o: is our object file generated from compiling complex.c in step 3

notice the generation of the library file libcomplex.a

5- we are done!, so let's examine the generated files before using the library.

First, we can use the command "nm" to see the symbols in our object file, use this command:
>nm complex.o
the output will be like:
00000000 T add
00000075 t assert_ptr_not_null
         U fwrite
         U stderr

Notice the existence of our functions (assert_ptr_not_null, add)

let's examine the library too:
>nm libcomplex.a 

complex.o:
00000000 T add
00000075 t assert_ptr_not_null
         U fwrite
         U stderr


6- now, lets use the libary, here's a test program that uses the library:

//program.c
#include <stdio.h>
#include <stdlib.h>

#include "complex.h"

int
main()
{
    
    complex_t *c1 = (complex_t*) malloc(sizeof (complex_t));
    complex_t *c2 = (complex_t*) malloc(sizeof (complex_t));
    
    c1->real = 10;
    c1->imaginary = 10;
    
    add(c1, c2);
    
    
    printf("%f\n", c1->real);
    printf("%f\n", c1->imaginary);
    
    printf("%f\n", c2->real);
    printf("%f\n", c2->imaginary);
    
    free(c1);
    free(c2);
    
    return 0;
}

first, we need to compile our program:
>cc -c program.c

then, it's time for linking the generated object file:
> cc -o program program.o -L. -lcomplex
-lcomplex: composed of "-l" + "complex" which is our library name (without both "lib" and ".a").
-L. : this instruct the linker (ld) to include the current directory among the paths it searches for locating object files/libraries. (so it can look in our libcomplex.a library)

this command will generate the binary file for us, it will be named "program", try executing it:

>./program

also, we can list symbols in this binary using th "nm" tool too.

thats all.

References:
Beginning Linux Programming, third edition, Wiley Publishing, Inc.

2 comments:

Anonymous said...

the ar step I failed, after reading another blog, using ar rcs works.

mhewedy said...

I think it might depend on Linux version you have.