Sunday, March 27, 2016

How to Build and Add Custom C Library

For those who are familiar with Matlab, you may know the functions tic and toc. These two functions are used to print out elapsed time in between tic and toc. Let us implement this in C and create a library, so that we can use these functions easily later.

First, create tictoc.c file with the following:
#include <tictoc.h>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>

/* indicates whether tic has been called */
static int tic_flag = 0;

/* tic timeval */
static struct timeval start;

void tic() {
    tic_flag = 1;
    if (gettimeofday(&start, NULL)) {
        fprintf(stderr, "libtictoc: error from gettimeofday()\n");
    }
}

void toc() {
    if (tic_flag == 0) {
        fprintf(stderr, "libtictoc: tic() has not been called\n");
        return;
    }
    struct timeval end;
    if (gettimeofday(&end, NULL)) {
        fprintf(stderr, "libtictoc: error from gettimeofday()\n");
        return;
    }
    printf("Time elapsed: %lfs\n", 
            (double) (end.tv_sec-start.tv_sec)
            + (double)(end.tv_usec-start.tv_usec)/1000000.0);
}


Next, create tictoc.h file with the following:
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

#ifndef _TICTOC_H_
#define _TICTOC_H_

extern void tic();
extern void toc();

#endif // _TICTOC_H_

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

Note that the first three lines and the last three lines in the header enable C++ compatibility.

Now, let's see if we can compile this
$ gcc -c -Wall  -I . tictoc.c
You should see it compile successfully, and tictoc.o file has been created.

Make sure you have binutils installed on the system. For Ubuntu/Debian, simply run
$ sudo apt-get install -y binutils

For Mac OS X, run
$ brew install binutils

To create a library file, we run
$ ar -cvq libtictoc.a tictoc.o

This command will use tictoc.o file to create libtictoc.a library file. To examine the newly created file, run
$ ar -t libtictoc.a
You should see tictoc.o file listed.

We are now ready to copy the library file and the header file into the default user library and include folders.
$ sudo cp libtictoc.a /usr/local/lib
$ sudo cp tictoc.h /usr/local/include

Finally, we test whether the library works well. Create a test.c file with the following:
#include <tictoc.h>
#include <unistd.h>
int main() {
    tic();
    sleep(1);
    toc();
    sleep(2);
    toc();
    return 0;
}


Let's try to compile it
$ gcc -Wall test.c
You should see some error saying undefined reference to tic and toc. This is because we have not told gcc to look for libtictoc library. 

Well, let's do it.
$ gcc -Wall -l tictoc test.c
The -l option tells gcc to search for library, and the proceeding string (tictoc) preceded by lib will be the name of the library. That means, -l tictoc is asking gcc to look for a library file named libtictoc within the default library folders. Since we have copied over libtictoc.a file into /usr/local/lib, which is one of the default library search folders, gcc will be able to locate it. To find out the default load library path is, look into /etc/ld.so.conf file.

Note that .a extension is used for static library whereas .so extension is used for dynamically linked library.

It should compile now. Let's run it and see if it actually works.
$ ./a.out
You wills see something like time elapsed 1s and 3s, just as you expected!

No comments:

Post a Comment