Why do I have to re-include header files in C when running Ceedling?

809 Views Asked by At

I have a C project which I intend to test with Ceedling, CMock, and Unity stack. I do have an issue when running tests...

My project structure is below

mytest
    ├── lib
    │   ├── bar.c
    │   └── include
    │       └── bar.h
    ├── project.yml
    ├── src
    │   ├── foo.c
    │   └── include
    │       └── foo.h
    └── test
        ├── support
        └── test_foo.c

And my Ceedling project.yml file

---

# Notes:
# Sample project C code is not presently written to produce a release artifact.
# As such, release build options are disabled.
# This sample, therefore, only demonstrates running a collection of unit tests.

:project:
  :use_exceptions: FALSE
  :use_test_preprocessor: TRUE
  :use_auxiliary_dependencies: TRUE
  :build_root: build
#  :release_build: TRUE
  :test_file_prefix: test_
  :which_ceedling: gem
  :ceedling_version: 0.31.1
  :default_tasks:
    - test:all

#:test_build:
#  :use_assembly: TRUE

#:release_build:
#  :output: MyApp.out
#  :use_assembly: FALSE

:environment:

:extension:
  :executable: .out

:paths:
  :test:
    - +:test/**
    - -:test/support
  :source:
    - src/**
    - src/include
    - lib/**
    - lib/include
  :support:
    - test/support
  :libraries: []

:defines:
  # in order to add common defines:
  #  1) remove the trailing [] from the :common: section
  #  2) add entries to the :common: section (e.g. :test: has TEST defined)
  :common: &common_defines []
  :test:
    - *common_defines
    - TEST
  :test_preprocess:
    - *common_defines
    - TEST

:cmock:
  :mock_prefix: mock_
  :when_no_prototypes: :warn
  :enforce_strict_ordering: TRUE
  :plugins:
    - :ignore
    - :callback
  :treat_as:
    uint8:    HEX8
    uint16:   HEX16
    uint32:   UINT32
    int8:     INT8
    bool:     UINT8

# Add -gcov to the plugins list to make sure of the gcov plugin
# You will need to have gcov and gcovr both installed to make it work.
# For more information on these options, see docs in plugins/gcov
:gcov:
  :reports:
    - HtmlDetailed
  :gcovr:
    :html_medium_threshold: 75
    :html_high_threshold: 90

#:tools:
# Ceedling defaults to using gcc for compiling, linking, etc.
# As [:tools] is blank, gcc will be used (so long as it's in your system path)
# See documentation to configure a given toolchain for use

# LIBRARIES
# These libraries are automatically injected into the build process. Those specified as
# common will be used in all types of builds. Otherwise, libraries can be injected in just
# tests or releases. These options are MERGED with the options in supplemental yaml files.
:libraries:
  :placement: :end
  :flag: "-l${1}"
  :path_flag: "-L ${1}"
  :system: []    # for example, you might list 'm' to grab the math library
  :test: []
  :release: []

:plugins:
  :load_paths:
    - "#{Ceedling.load_path}"
  :enabled:
    - stdout_pretty_tests_report
    - module_generator
...

bar.h:

int addMe(int a, int b);

bar.c:

#include "bar.h"

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

foo.h:

#ifndef FOO_H
#define FOO_H

    int addMore(int a, int b, int c);

#endif // FOO_H

foo.c:

#include "bar.h"
#include "foo.h"

int addMore(int a, int b, int c)
{
    return addMe(a, b) + c;
}

My test file test_foo.c looks like this:

#include "unity.h"
#include "foo.h"

void setUp(void)
{
}

void tearDown(void)
{
}

void test_foo_addMore(void)
{
    printf("%d", addMore(1, 2, 3));
}

Running ceedling test:all I get an error that says this:

/usr/bin/ld: build/test/out/c/foo.o: in function `addMore':
/home/USER/mytest/src/foo.c:6: undefined reference to `addMe'

If Include the bar.h header file everything works, but why do I have to do this? I included foo.h where bar.h is already included.

I added the src/include bin bin/include file paths to the project.yml as well.

So, why is this?

Tried setting up the project the way I described and it did not act in the way I thought it would.

1

There are 1 best solutions below

0
On

If Include the bar.h header file everything works, but why do I have to do this?

Because that is how Ceedling works. From the documentation:

Ceedling knows what files to compile and link into each individual test executable by way of the #include list contained in each test file. Any C source files in the configured search directories that correspond to the header files included in a test file will be compiled and linked into the resulting test fixture executable.

So, you need to explicitly include header file into test source file, so that Ceedling knows which source files to compile. If you include bar.h, then it will look for bar.c. Note that build will fail if your .c file is called something else, like bar_new.c.