Search code examples
ccmakecliondirectory-structure

Structuring C Project with CMake and Clion


I have the following project structure within clion:

├── CMakeLists.txt
├── src
│   ├── func1.c
│   ├── func1.h
│   └── main.c
└── test
    └── unit
        └── test_func1.c

Where CMakeLists.txt:

    cmake_minimum_required(VERSION 3.5)
    project(untitled)

    set(CMAKE_C_STANDARD 11)
    find_library(CMOCKA_LIBRARY libcmocka.so)

    # application binary
    set(SOURCE_FILES src/main.c src/func1.c src/func1.h)
    add_executable(untitled ${SOURCE_FILES})

    # test binary
    include_directories("${CMAKE_SOURCE_DIR}/src")
    set(TEST_SOURCE_FILES src/func1.c src/func1.h test/unit/test_func1.c)
    add_executable(unit_tests ${TEST_SOURCE_FILES})
    target_link_libraries(unit_tests ${CMOCKA_LIBRARY})

main.c:

#include <stdio.h>
#include "func1.h"

int main() {
  printf("Hello, World!\n");
  print_hello();
  return 0;
}   

test_func1.c:

    #include <stdlib.h>
    #include <stdarg.h>
    #include <stddef.h>
    #include <setjmp.h>
    #include <cmocka.h>
    #include "func1.h"

    static void test_func1(void **state){
      int ret = print_hello();
      assert_true(ret == 0);

    }

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

      const UnitTest tests[] = {
          unit_test(test_func1),
      };

      return run_tests(tests);
    }

func1.c:

    #include <stdio.h>
    #include "func1.h"

    int print_hello(){
      printf("hello");
      return 0;
    }

func1.h:

    #ifndef UNTITLED_FUNC1_H
    #define UNTITLED_FUNC1_H

    int print_hello();

    #endif //UNTITLED_FUNC1_H

When I build the application from within clion, it only builds the untitled application binary, and it does not build the test binary. In order to build the test, I have to create a build directory and invoke cmake and make by hand.

I would like to:

  1. Have clion build both the application binary and test binary on "build"
  2. Only build application binary if tests pass
  3. What would be a better way of managing unit tests in this case

Solution

  • Have clion build both the application binary and test binary on "build"

    In the upper right corner of the CLion main window you can select your current configuration from a drop-down menu. This should include both your main and test executable targets, along with a special configuration called Build All.

    The configuration select drop down

    Change this to Build All and it will build all your targets at once. Note that you cannot 'Run' the Build All configuration, unless you also tell CLion explicitly which executable you want it to run here.

    Only build application binary if tests pass

    This is not possible. Building is building and running tests is running tests. Building comes strictly before running. Therefore the outcome of a run cannot influence the build, unless you create some (very) elaborate boilerplate construct.

    What would be a better way of managing unit tests in this case

    Currently to both CMake and CLion your unit tests are an executable like any other. You can use CTest to register them as proper tests, which gives you some nice additional support from the IDE. Take a look at the enable_testing and add_test commands in CMake.