ThrowTheSwitch / Ceedling

Ruby-based unit testing and build system for C projects

Home Page:http://throwtheswitch.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Option to compile all files and then run the tests

Osanti22 opened this issue · comments

Hello everyone. I have a large project with multiple .c and .h files, and I want to compile EVERYTHING in the directory before running the tests. (I'm semi noob on C)

Lets say a have a functions in functions1.c
Then I have headers in functions1.h
But I may need to initialize some variables in config.c
config.h includes many .h files, that and uses initialization from many .c files.

Is there any alternative to including all files in the project on each test?
I would just like to compile everything in the source, and the just run functions. Is there a function in Ceedling to do this?

Usually I use Keil to compile everything, so I don't have much experience with bundling files and directories together to make gcc compile them.

I'd appreciate some guidance.

The most annoying issue is that lets say I want to compile config.c

If I just include config.h, the compiler won't include the things included on config.c (or config.h), so I would have to look for each one of those. And then, those may depend on other .h or .c files.

It's like the linker cannot find the includes of the included, if you know what I mean.

You are presenting this very confusingly. Maybe this will help:

You have compiler (compiles source (.c) files), which has its own include paths to find correct header files. This is mostly called gcc, but in fact it is wrapper around cc (little known).

You have a linker (links object (.o) files), which also has its own include paths to find the correct object files and basically concatenates them together into a big blob binary (simple explanation). This is mostly ld, but maybe it added to the confusion is the fact that gcc provides a wrapper around it. That means you can call gcc to compile & link.

Based on above, you are complaining that compiling is not working, but you are saying it is a linker issue (meaning all files correctly compiled, but cannot be glued together into a test binary)? So on which stage it is failing? For sake of mocking (and simplicity), try to avoid config.h which includes 10 other header files and it is included in each other header file, but rather have needed header files included directly. That way you can mock external components easily (this is how I understood your explanation of the common header file).

I might be misunderstanding, but it sounds like the main issue you're running into is that the things you want to test have dependencies in other modules?

Things that can be done:

  • If you need a global variable defined elsewhere for your test to run, you can define it in your test.
  • If the code you are testing calls functions which are defined elsewhere, you can tell ceedling to build and include a mock instead of the real version.
  • If there are types defined elsewhere, it's best to directly include them... but if that include means you also have to include a bunch of other stuff, you CAN create headers which are slimmed down versions of your full system files, and just use them for tests.

If you find yourself doing a lot of this sort of thing, honestly it's a "code smell". It tells you that the project you're testing has poor encapsulation (it has too many connections between modules). If you're in a position where you can refactor your source code, often small changes will create big improvements. If not, the tips above help reduce the pain.

You are presenting this very confusingly. Maybe this will help:

You have compiler (compiles source (.c) files), which has its own include paths to find correct header files. This is mostly called gcc, but in fact it is wrapper around cc (little known).

You have a linker (links object (.o) files), which also has its own include paths to find the correct object files and basically concatenates them together into a big blob binary (simple explanation). This is mostly ld, but maybe it added to the confusion is the fact that gcc provides a wrapper around it. That means you can call gcc to compile & link.

Based on above, you are complaining that compiling is not working, but you are saying it is a linker issue (meaning all files correctly compiled, but cannot be glued together into a test binary)? So on which stage it is failing? For sake of mocking (and simplicity), try to avoid config.h which includes 10 other header files and it is included in each other header file, but rather have needed header files included directly. That way you can mock external components easily (this is how I understood your explanation of the common header file).

Ok. It helps to understand what is going on on the background, Thanks.
After re reading your comment a thousand times, my findings are:

  1. Ceedling is finding and creating objects of the correct files.

  2. After building, the step "Building Test Executables" fails with some errors like:

production_code1.c:88: undefined reference to MMath_Sqrt'

or

undefined reference to PID_Reset'

However, those functions should be included since they were successfully made objects of.

image

EDIT: it seems that it's not treating the production code very well.

Like I said earlier

production_code.c depends on other code like pid_controller.c. But even though objects of pid_controller.c and production_code.c are created, when it comes to running a function on the production code, functions of pid_controller.c are not recognized.

Always treat errors in sequence. For the math, you are missing -lm flag to linker.

Use ceedling verbosity[4] test:all to increase debug output of ceedling for that PID_Reset (is that function or variable?)

Always treat errors in sequence. For the math, you are missing -lm flag to linker.

Use ceedling verbosity[4] test:all to increase debug output of ceedling for that PID_Reset (is that function or variable?)

Verbosity helped a lot.
The test fails when it tries to link all the .o files. It says undefined reference. I checked the order, and seemed fine.

I tried including the pid_controller.o file twice in the gcc linking command, and it says
multiple definition of .weak.PID_Init which is a function. So it sees the function. Lower in the error code, it says again undefined reference. So it is weird that it will complain that it's defined twice, and below that it complains that it's not defined.

My worry was also that it was only seeing the .h file, and not the .c, but if I go to the dependencies (pid_controller.d), then I see that pid_controller.c is included. The functions headers are in the .h file and the contents are in the .c file.

Anyway, thanks a lot for the help. It looks like a gcc / code issue, not ceedling.