2009-10-13

Back to C: CMake and CUnit

I'm back at programming in C. I proposed something 8 months ago at work that was totally ignore. Now my boss wants me to do it because the other alternatives have totally failed. The idea is to implement an ODBC Driver. If I have the time I'll put a tutorial here on how to do that on Linux. But back to the point of this entry.

This small guide will help you create a simple project using CMake to build it and cunit to test it. Yes, I believe in test driven development, no matter the language.

Let's imagine a simple project that produces an executable that prints the result of 2 + 3 (I know, lame but sufficient for this example). To make it easier to test I split the application. The functions will go into a library and there will be a source file that starts the program. The library header file is called "lib.h" (extra points for originality). Here are its contents:
int add(int a, int b);

The implementation is on the lib.c file as follows:
int add(int a, int b) {
return a + b;
}

As you can see it is a very complicated function. The adder.c file contain the main function and starts the program as follows:
#include <stdio.h> 
#include "lib.h"

int main (int argc, char** argv) {
printf("2+3=%d\n", add(2, 3));
return 0;
}

The unit test is a little more complicated as cunit requires some boiler plate code in order to run tests. Here is the source code of the test_lib.c file:
#include "CUnit/Basic.h" 
#include "lib.h"

void simpleTest(void) {
CU_ASSERT(2 == add(1, 1));
}

int main (int argc, char** argv) {

CU_pSuite pSuite = NULL;

/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();

/* add a suite to the registry */
pSuite = CU_add_suite("Suite_1", NULL, NULL);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}

/* add the tests to the suite */
if (NULL == CU_add_test(pSuite, "Simple Addition Test", simpleTest)) {
CU_cleanup_registry();
return CU_get_error();
}

/* Run all tests using the CUnit Basic interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}

To make all this build with CMake you have to create a CMakeLists.txt file with the following content:
cmake_minimum_required (VERSION 2.6)
project (Adder)

set (SOURCES lib.c)

add_executable (adder adder.c ${SOURCES})

enable_testing ()

add_executable (test_lib test_lib.c ${SOURCES})

set_target_properties (test_lib PROPERTIES LINK_FLAGS -Wl,-lcunit)

add_test (test_lib ${EXECUTABLE_OUTPUT_PATH}/test_lib)


And that is it. Now you can make a directory called "build", go into to it and type "cmake .." to generate all the necessary build files. To build the project you type "make", to run the tests you can type "make test" and to clean the output you can run "make clean". If you prefer to do it all in one pass just do "make clean all test".

Just in case you are wondering: I used c2html to generate the html formated version of the C files and VIMs convert-to-html script for the CMake file.

Happy coding!!!