-
-
Notifications
You must be signed in to change notification settings - Fork 262
Description
I am working on a big firmware project where Ceedling is used to run unittests and mock driver headers.
The issue I am having is that if I enable the test preprocessor feature and have CMock configured to treat header files with inline functions (of which we have some) the compilation of the unittest fails.
Additional info specific to our project is that the unittests (and project.yml file) are located in a separate directory so I am doing CEEDLING_MAIN_PROJECT_FILE=./unittests/project.yml before calling Ceedling.
I was able to recreate the issue using a simple example project that contains only a few files - https://github.com/i-adamov/ceedling-issue-example
I have a module which I need to test (./src/example_file.c and ./inc/example_file.h) which includes a driver header (./driverv/drv_bbb.h) and in turn the driver header includes a HAL header (./driver/hal/hal_aaa.h). This simulates how our project is structured.
There is another header (./inc/other_header.h) which also includes the driver header and it is also included by the example_file module. It simulates the header of another module that may interact with the module I am testing.
When running Ceedling without the preprocessing it works fine:
export CEEDLING_MAIN_PROJECT_FILE=./unittests/project.yml ; ceedling clobber test:all
Clobbering all generated files...
(For large projects, this task may take a long time to complete)
Test 'test_unittest.c'
----------------------
Creating mock for drv_aaa...
Generating runner for test_unittest.c...
Compiling test_unittest_runner.c...
Compiling test_unittest.c...
Compiling mock_drv_aaa.c...
Compiling unity.c...
Compiling cmock.c...
Linking test_unittest.out...
Running test_unittest.out...
[==========] Running 2 tests from 1 test cases.
[----------] Global test environment set-up.
[----------] 2 tests from test_unittest.c
[ RUN ] test_unittest.c.test_func1
[ OK ] test_unittest.c.test_func1 (0 ms)
[ RUN ] test_unittest.c.test_static_func2
[ OK ] test_unittest.c.test_static_func2 (0 ms)
[----------] 2 tests from test_unittest.c (0 ms total)
[----------] Global test environment tear-down.
[==========] 2 tests from 0 test cases ran.
[ PASSED ] 2 tests.
[ FAILED ] 0 tests.
0 FAILED TESTS
0 FAILED TESTS
However if I set :use_test_preprocessor: TRUE the build fails:
Clobbering all generated files...
(For large projects, this task may take a long time to complete)
Test 'test_unittest.c'
----------------------
Generating include list for drv_aaa.h...
Creating mock for drv_aaa...
In file included from unittests/build/test/mocks/mock_drv_aaa.h:6:0,
from unittests/test/test_unittest.c:3:
unittests/build/test/mocks/drv_aaa.h:1:10: fatal error: driver/hal/hal_bbb.h: No such file or directory
#include "driver/hal/hal_bbb.h"
^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
ERROR: Shell command failed.
> Shell executed command:
'gcc -E -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"unittests/build/test/mocks" -I"unittests/test" -I"unittests/test/support" -I"src" -I"inc" -I"driver/inc" -I"driver/hal" -D__STATIC_INLINE="static inline" -DTEST -D__STATIC_INLINE="static inline" -DTEST -DGNU_COMPILER "unittests/test/test_unittest.c" -o "unittests/build/test/preprocess/files/test_unittest.c"'
> And exited with status: [1].
rake aborted!
ShellExecutionException: ShellExecutionException
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/tool_executor.rb:88:in `exec'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/preprocessinator_file_handler.rb:12:in `preprocess_file'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/preprocessinator.rb:48:in `preprocess_file'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/preprocessinator.rb:12:in `block in setup'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/preprocessinator_helper.rb:37:in `preprocess_test_file'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/preprocessinator.rb:33:in `preprocess_test_and_invoke_test_mocks'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:84:in `block in setup_and_invoke'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/test_invoker.rb:51:in `setup_and_invoke'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/tasks_tests.rake:13:in `block (2 levels) in <top (required)>'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/bin/ceedling:345:in `block in <top (required)>'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/bin/ceedling:332:in `<top (required)>'
/usr/local/bin/ceedling:23:in `load'
/usr/local/bin/ceedling:23:in `<main>'
Tasks: TOP => test:all
(See full trace by running task with --trace)
ERROR: Ceedling Failed
What I see as a difference is that the driver header file (unittests/build/test/mocks/drv_aaa.h) which is processed by CMock to make the inline functions testable has changes to the include macros in the top of the file. It is also missing its include guard.
When running without preprocessor:
#ifndef DRV_AAA_H
#define DRV_AAA_H
#include "hal_bbb.h"
#define AAA 10
int get_aaa(void);
#endif
When running with preprocessor (empty lines truncated):
#include "driver/hal/hal_bbb.h"
int get_aaa(void);
The use of this driver/hal/hal_bbb.h filepath makes it impossible for the compiler to locate the file as the root directory is not used as an include path. However if I add it to the :paths: :include: section of the project.yml file, I get another issue with undefined macros:
Clobbering all generated files...
(For large projects, this task may take a long time to complete)
Test 'test_unittest.c'
----------------------
Generating include list for drv_aaa.h...
Creating mock for drv_aaa...
Generating runner for test_unittest.c...
Compiling test_unittest_runner.c...
Compiling test_unittest.c...
In file included from unittests/test/test_unittest.c:4:0:
src/example_file.c: In function 'func1':
inc/other_header.h:6:20: error: 'AAA' undeclared (first use in this function)
#define SOMETHING (AAA + 5)
^
src/example_file.c:13:24: note: in expansion of macro 'SOMETHING'
return a + b + x + SOMETHING;
^~~~~~~~~
inc/other_header.h:6:20: note: each undeclared identifier is reported only once for each function it appears in
#define SOMETHING (AAA + 5)
^
src/example_file.c:13:24: note: in expansion of macro 'SOMETHING'
return a + b + x + SOMETHING;
^~~~~~~~~
unittests/test/test_unittest.c: In function 'test_func1':
inc/other_header.h:6:20: error: 'AAA' undeclared (first use in this function)
#define SOMETHING (AAA + 5)
^
unittests/test/test_unittest.c:25:36: note: in expansion of macro 'SOMETHING'
int expected = a + x * x + x + SOMETHING;
^~~~~~~~~
ERROR: Shell command failed.
> Shell executed command:
'gcc -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/unity/src" -I"/var/lib/gems/2.5.0/gems/ceedling-0.31.1/vendor/cmock/src" -I"unittests/build/test/mocks" -I"unittests/test" -I"unittests/test/support" -I"src" -I"." -I"inc" -I"driver/inc" -I"driver/hal" -D__STATIC_INLINE="static inline" -DTEST -DGNU_COMPILER -g -c "unittests/test/test_unittest.c" -o "unittests/build/test/out/c/test_unittest.o" -MMD -MF "unittests/build/test/dependencies/test_unittest.d"'
> And exited with status: [1].
#<Thread:0x0000556d90ed87c8@/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/par_map.rb:7 run> terminated with exception (report_on_exception is true):
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/tool_executor.rb:88:in `exec': ShellExecutionException (ShellExecutionException)
from /var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/generator.rb:99:in `generate_object_file'
from /var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/rules_tests.rake:17:in `block in <top (required)>'
from /usr/lib/ruby/vendor_ruby/rake/task.rb:271:in `block in execute'
from /usr/lib/ruby/vendor_ruby/rake/task.rb:271:in `each'
from /usr/lib/ruby/vendor_ruby/rake/task.rb:271:in `execute'
from /usr/lib/ruby/vendor_ruby/rake/task.rb:213:in `block in invoke_with_call_chain'
from /usr/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'
from /usr/lib/ruby/vendor_ruby/rake/task.rb:193:in `invoke_with_call_chain'
from /usr/lib/ruby/vendor_ruby/rake/task.rb:182:in `invoke'
from /var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/task_invoker.rb:97:in `block in invoke_test_objects'
from /var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/par_map.rb:10:in `block (2 levels) in par_map'
rake aborted!
ShellExecutionException: ShellExecutionException
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/tool_executor.rb:88:in `exec'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/generator.rb:99:in `generate_object_file'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/rules_tests.rake:17:in `block in <top (required)>'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/task_invoker.rb:97:in `block in invoke_test_objects'
/var/lib/gems/2.5.0/gems/ceedling-0.31.1/lib/ceedling/par_map.rb:10:in `block (2 levels) in par_map'
Tasks: TOP => unittests/build/test/out/c/test_unittest.o
(See full trace by running task with --trace)
ERROR: Ceedling Failed
What am I doing wrong? Do I need to enable some of the other Ceedling setting?
I need to be able to preprocess macros and to mock static functions in header files.
Metadata
Metadata
Assignees
Type
Projects
Status