0

I have a simple test code suite set up in the C language to provide a template for the use of CMake to simultaneously build unit tests with cmocka and also build the integrated code in the main.c file. The code has the following directory structure, where the main.c file integrates code, the functions are contained in the include directory, the build directory contains the build files (i.e. makefile) and the exectable, as well as the test executable in a test directory. In this simple example I am trying to build the test code for the add.h and add.c files with cmocka

apples
|__ CMakeLists.txt
|__ main.c
|__ include
|   |__ CMakeLists.txt
|   |__ add.c
|   |__ add.h
|__ build
|   |__ apples (executable)
|   |__ test
|       |__ unit_tests (executable)
|__ test
    |__ CMakeLists.txt
    |__ test_add.h
    |__ test_add.c
    |__ unit_test.c

I am trying to get this build configuration to work with CMake, and I can make create the apples executable in the build directory. However, I am not sure how to link cmocka to the CMake build and cannot get that part to work. In order to ensure that cmocka is working properly I cd'd to the test directory and manually built it with the gcc unit_tests.t test_add.c ../include/add.c -lcmocka command, and it compiled correctly. I am listing the contents of each file below.

CMakeLists.txt file in the apples directory

# CMake version
cmake_minimum_required(VERSION 3.22.2)
project(apples)

# Set the compiler, for some reason this does not work with clang++ or g++
set(CMAKE_C_COMPILER "/usr/bin/gcc")

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

enable_testing()
set(CMAKE_C_FLAGS "-Wall -Werror -Wpedantic -std=c11 -lcmocka")
# --------------------------------------------------------------------------------
# Set executable terms

# Specify directory where the executable is stored
# set(CMAKE_CURRENT_BINARY_DIR "bin")

# Add subdirectories
add_subdirectory(include)

# Create name for executable
add_executable(${PROJECT_NAME} main.c)

# Add target libraries if necessary
target_link_libraries(${PROJECT_NAME} PUBLIC include)
# --------------------------------------------------------------------------------
# Set test terms

add_subdirectory(test)

CMakeLists.txt file in the include directory

add_library(include
    add.c
    add.h
)

target_include_directories(include PUBLIC .)

CMakeLists.txt file in the test directory

cmake_minimum_required(VERSION 3.22.2)

enable_testing()

add_executable(
  unit_test.c
  test_add.c
  test_add.h
)
target_link_libraries(
  include
)

add.c #include "add.h" float float_add(float a, float b) { return a + b; }

int int_add(int a, int b) {
    return a + b;
}

add.h

#ifndef add_H
#define add_H

#include <stdio.h>

float float_add(float a, float b);
int int_add(int a, int b);

#endif /* add_H */

test_add.c

#include "test_add.h"
void test_i_add(void **state)
{
    (void) state;
    int a = 5;
    int b = 2;
    int c = int_add(a, b);
    assert_int_equal(c, 7);
}

void test_f_add(void **state)
{
    float a = 3.2;
    float b = 2.1;
    float c = float_add(a, b);
    assert_float_equal(c, 5.3f, 1.0e-3);
}

test_add.h

#ifndef addtest_H
#define addtest_H

#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdint.h>
#include <cmocka.h>

#include "../include/add.h"

void test_i_add(void **state);
void test_f_add(void **state);

#endif /* addtest_H */

unit_test.c

#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdint.h>
#include <cmocka.h>

#include "test_add.h"

// Begin code
int main(int argc, const char * argv[]) {
    const struct CMUnitTest add_tests[] = {
        cmocka_unit_test(test_i_add),
        cmocka_unit_test(test_f_add)
    };
    return cmocka_run_group_tests(add_tests, NULL, NULL);
}

I am excluding the main.c file in the apples directory, since it is irrelevent to the cmocka build. Unfortunately the CMake setup in the CMakeLists.txt files is not correct, and will not build the unit tests with cmocka. However, I am not sure in what way I am supposed to modify the CMakeLists.txt files. I am assuming that the upper most CMakeLists.txt file should reference cmocka, but I am not sure how, or if this should occur in the CMakeLists.txt file in the test directory. Any suggestions or guidance would be greatly appreciated.

Jon
  • 1,621
  • 5
  • 23
  • 46
  • In your `test/CMakeLists.txt`, you should give a name to your executable. `add_executable(targetName unit_test.c ...etc)`. Then, you must link your targetName to your `include` target `target_link_libraries(targetName PRIVATE include)` – Martin Aug 31 '22 at 11:41
  • On a side note, adding -lcmocka to your CMAKE_C_FLAGS is not the best because it affects all your project, even then target that don't need it. The best is to restrict to needed target. You can used `target_link_libraries(targetName PRIVATE cmocka)` – Martin Aug 31 '22 at 11:43
  • Why was this question closed? The alleged previously answered question is based on how to add a flag to CMake, which is not what I asked. – Jon Aug 31 '22 at 15:06
  • @Martin despite my answer being closed for reasons that had little to do with my question, your response helped me figure out what was going wrong. If there is any way I can credit you for helping me solve this, please let me know. – Jon Aug 31 '22 at 15:28
  • Agree, don't really understand why it's marked as dupplicate. Glad you solved it :) – Martin Aug 31 '22 at 20:42
  • You provide a command line which works for you: `gcc unit_tests.t test_add.c ../include/add.c -lcmocka`. And provide `CMakeLists.txt`, which doesn't work for you: "Unfortunately the CMake setup in the `CMakeLists.txt` files is not correct, and will not build the unit tests with cmocka.". This is because you incorrectly attempt to link with cmocka by setting `CMAKE_C_FLAGS` variable. The [referenced question](https://stackoverflow.com/questions/43136418/how-to-add-l-ell-compiler-flag-in-cmake) shows the similar attempt, and this is why I marked your question as duplicate. – Tsyvarev Sep 01 '22 at 11:18
  • It is true that your code has also other problems, like missed linking target in `target_link_libraries(include)` call or setting `CMAKE_C_COMPILER` variable after the `project()` call (https://stackoverflow.com/a/63944545/3440745). But you ask specifically about linking with cmocka, and the duplicate question reflects this. (Asking "why my code doesn't work" in *general*, without showing the **error message** and debugging attempts, wouldn't fit for Stack Overflow at all.) – Tsyvarev Sep 01 '22 at 11:27

0 Answers0