Short introduction to use of external libraries

This tutorial will show how to use external libraries within your code. We will create an application, that creates a window and draws sinc pulse into it. To create the window and the drawing we use library called SDL (Simple DirectMedia Layer). Our focus is not to completely explain how this library works, rather to show how the use of external libraries is done in general.

To begin with we create sinc.c module, which is used to calculate the values of sinc function as parameter of time. We need to import math.h to use the sin function.

sinc.h
#ifndef SINC_H
#define SINC_H

#include <math.h>

float sinc(float t);

#endif
sinc.c
#include "sinc.h"
#define SINC_PI "3.14159265"


float sinc(float t)
{
    if (!t)
    {
        return 1;
    }
  return sin(SINC_PI * t) / (SINC_PI * t);
}

To compile

    gcc -c sinc.c -Wall -Wextra -std=c99 // ( 1

( 1 If you are compiling with --std=c99 you need to define constant for pi by yourself

Drawsinc module will initialize the SDL library, create the window, update framebuffer (ie. draw sinc pulse into it), process events, update the window (so that the sinc pulse is actually drawn) and finally call the exit handler of the library.

drawsinc.h
#ifndef DRAWSINC_H
#define DRAWSINC_H

#include <stdlib.h>
#include <stdio.h>
#include <SDL.h>

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define COLOR_DEPTH 32

void put_pixel( SDL_Surface *surface, int x, int y, int color );
void draw_sinc(SDL_Surface *screen, int screen_width, int screen_height);

#endif

In header file drawsinc.h we include header files from standard library (stdlib.h, stdio.h) and one header file from SDL library (SDL.h). This allows us to use data types defined in SDL library (such SDL_Surface).

drawsinc.c
#include "sinc.h"
#include "drawsinc.h"

void put_pixel( SDL_Surface *surface, int x, int y, int color ) {
    if (x < 0 || x > SCREEN_WIDTH)
        return;
    if (y < 0 || y > SCREEN_HEIGHT)
        return;
    unsigned int *pixels = (unsigned int *)surface->pixels;
    int lineoffset = y * (surface->pitch / 4);
    pixels[ lineoffset + x ] = color;
}

void draw_sinc(SDL_Surface *screen, int screen_width, int screen_height)
{
  int x;
  for (x=0; x<screen_width; x++) {
    float sincvalue = 100*sinc(((float)(x - (screen_width / 2)))/10.0);
    put_pixel(screen, x, screen_height / 2 + -1 * sincvalue, 0x00ff00);
  }
}

int main(int argc, char *argv[]) 
{
  int running = 1;
  int flags = SDL_SWSURFACE;
  SDL_Surface *screen;
  SDL_Event event;
  SDL_Init(SDL_INIT_EVERYTHING);
  screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_DEPTH, flags);
  while (running) {
    while (SDL_PollEvent(&event)) {
      switch(event.type) {
        case SDL_KEYDOWN:
        case SDL_QUIT:
	        running = 0;
        	break;
        default:
	        break;
      }
    }
    draw_sinc(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
    SDL_Flip(screen);
  }
  SDL_Quit();
  return EXIT_SUCCESS;
}

Some libraries require initialization before they can be used. That is the with SDL too, so in main function after the variable declarations we call function SDL_Init. Function definition is visible here, because we introduced it with other standard SDL functions when we included header file SDL.h.

Precompiler is able to find all standard header files without any help from developer. These are usually located in /usr/include directory (such as /usr/include/stdlib.h). When using other libraries you most often need to tell to precompiler where to find required header files. GCC for example has handle "-I <path>", where path is directory where these header files are located.

Compiler is able to finish its job with the information (function prototypes, data types, ...) it got from header files. But to create executable, we need to tell linker where to find the actual bodies for these library functions. GCC expects to find these from file starting with string "lib", so to link the executable with SDL library we give "-l SDL" handle to GCC. We can also specify the directory from where to search this library file with "-L <path>" handle.

Some libraries also provide binaries to ease the compilation. SDL for example is distributed with application "sdl-config", which can find the compiler handles required to compile the application with SDL.

To compile

    gcc -c drawsinc.c -I /usr/include/SDL -Wall -Wextra -std=c99
     or
    gcc -c drawsinc.c `sdl-config --cflags` -Wall -Wextra -std=c99
    
gcc -o drawsinc sinc.o drawsinc.o -lm -lSDL -L /usr/lib or gcc -o drawsinc sinc.o drawsinc.o -lm `sdl-config --libs`