Lab 9 (Part-I): Building a C Library


This lab has two parts

  1. Creating a library (package) from the code written in the previous labs
  2. Using the library (package) to solve a set of problems covering the entire space of numerical methods learnt thus far. Use this Link for the Problem Set


Building a C Library

Let us covert all the C programs written by you into a library. It is a four-step process.

  1. Prepare your C source code files
    • Create a new directory with a name of your choice. I will use the name cbnm2023 as an example.
    • Copy all your C source files into the newly created directory.
    • Move into the new directory.

      Go through your C files and remove any main() functions from them.

  2. Create a header file

    The header file, ideally, should have the same name as that of the library you want to create. I want my library to be called cbnm2023. So, I will name the header file cbnm2023.h You can name your header file accordingly. Your header file must be like the one shown in the cell below. It should have a prototype declaration for every function you wrote in all the C files that you worked with in the previous step. Of course, the header file shown below contains the names of the functions that I wrote but you get the idea.

    What the header file can and cannot have!
    • include standard files such as stdio.h, stdlib.h, malloc.h, string.h, math.h etc.
    • any defined constants using #define directives.
    • all function prototype declarations. Make sure every function from your library is declared in the header file.
    • header file MUST NOT HAVE any global variable declarations and C code. Global variables must be carefully handled and that is why it is good to avoid them at this stage. If you include C code, then that is a cardinal sin - I will cut at least 10 marks from your internals!
  3. Compile each source file independently

    Insert the line

    #include "<your header file>.h"
    in all your C source files. Compile your C source files (without the main() functions in them separately. Use the following command on Linux
    gcc -c -fPIC <C source file name>
    This will result in a .o file corresponding to each source file.

  4. Create a shared object file library

    The last step in creating the library is to combine all the .o files into one library file. This is done by using the command

    gcc -shared -o libcbnm2023.so *.o
    This will create a library file named libcbnm2023.so. You can change it to any name but it should be of the form lib<your choice name>.so

  5. Test your library!

    Modify the code below (in Cell 3) for finding roots of an equation with your own functions. Copy it into a file root_main.c. Compile it now with the command

    gcc -o rootfind -L. root_main.c -lcbnm2023 -lm

    If it gives the correct answer, you are done.

You can also get an error saying that the library is not found. In that case, do the following

  1. Open the file .bashrc in your home directory in a text editor.
  2. Add the line
    export LD_LIBRARY_PATH=:<your directory name containg the library file>:
    at the end of the file. Save it.
You are done - try again and it should work! These instructions are for Linux. If you are using Windows, you will have to type the LD_LIBRARY_PATH command in a command terminal with appropriate changes.

Congratulations on your first library!


In [ ]:
/************************************************************************
 *  This is the header file for the functions in the cbnm library.
 *  The library comprises functions at various levels
 *  1.  Basic Matrices and Vectors
 *  2.  Matrix Operations
 *  3.  Root Finding
 *  4.  Systems of Equations
 *  5.  Regression
 *  6.  Interpolation
 *  7.  Integration
 *  8.  Ordinary Differential Equations
 *                                 - Author: Chakravarthy Bhagvati (2023)
 ************************************************************************/
#define ROWS(M)    (M->nrows)
#define COLS(M)    (M->ncols)

typedef struct {
    double *val;
    int length;
} VECTOR;

typedef struct {
    double **array;
    int nrows;
    int ncols;
} MATRIX;

typedef double DFUNC(double);          /* This defines functions for
                                          root finding code             */ 
/************************************************************************
 * The following are the Level 1 functions: matrix and vector basics
 ************************************************************************/
MATRIX *new_matrix(int, int, double);
MATRIX *mat_identity(int);
MATRIX *mat_transpose(MATRIX *);
MATRIX *new_random_matrix(int, int, ...);
MATRIX *mat_copy(MATRIX *);
MATRIX *vector_to_matrix(VECTOR *);
MATRIX *mat_set(MATRIX *, ...);
MATRIX *mat_get_slice(MATRIX *, int, int, int, int);
MATRIX *mat_concat_col(MATRIX *, VECTOR *);

VECTOR *mat_get_diagonal(MATRIX *);
VECTOR *new_vector(int, double);
VECTOR *vec_set(VECTOR *, ...);
VECTOR *mat_get_row(MATRIX *, int);
VECTOR *mat_get_column(MATRIX *, int);
VECTOR *vec_vrange(int, int, double);

double mat_get_value(MATRIX *, int, int);
double mat_set_value(MATRIX *, int, int, double);
void mat_print(MATRIX *);
void vec_print(VECTOR *);
/************************************************************************/
MATRIX *mat_add_scalar(MATRIX *, double);
MATRIX *mat_divide_scalar(MATRIX *, double);
MATRIX *mat_mult_scalar(MATRIX *, double);
MATRIX *mult_pairwise(MATRIX *, MATRIX *);
MATRIX *mat_mult(MATRIX *, MATRIX *);
VECTOR *vec_index(MATRIX *, double);
double mat_getmax(MATRIX *);
double mat_getmin(MATRIX *);
double mat_getmean(MATRIX *);
int vec_argmax(VECTOR *, int, int);
/************************************************************************/
double root_bisection(DFUNC *func, float low, float high, 
                      double eps, int maxiter);
double root_secant(DFUNC *func, float init, 
                   double eps, int maxiter);
/************************************************************************/
MATRIX *mat_vandermonde(VECTOR *, int);
MATRIX *cbnm_gauss_eliminate(MATRIX *);
MATRIX *cbnm_back_substitute(MATRIX *);
In [ ]:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "cbnm2023.h"

double *fifth_root100(double x)
{
    double x5 = pow(x, 5.0);
    
    return(x5 - 100.0);
}

int main(void)
{
    double ans;
    
    ans = root_bisection(fifth_root100, 1.0, 10.0, 0.000001, 50);
    printf("The fifth root of 100.0  is %lf\n", ans);
    printf("Verification:\n\t");
    printf("Calculated answer**5 = %lf\n", pow(ans, 5.0));
    
    exit(0);
}