Reputation:
I am developing for embedded systems with C and have setup an environment such that I am able to test locally without the target platform, enabled by #define TESTING_ENABLED
.
This will be extended shortly to include all aspects of the project, so managing each test definition may become tedious when switching between platforms.
Am I able to set a #define directive
through a makefile or detect the use of different compilers?
Upvotes: 0
Views: 150
Reputation: 979
Using #define
and #if
for that purpose is usually a very bad idea for several reasons, code becomes:
1. unreadable;
2. unportable;
3. unmaintainable;
The general rule of thumb is you can have #define
and #if
in header files only. As soon as preprocessors goes into source files it's become a clear path to a project failure in terms of maintenance and portability.
So, avoid at all costs, the code like this:
void foo()
{
...
#if TARGET_REAL_CPU
...
#endif
...
}
As an extreme example I've seen a code:
bool some_func(
int index,
#if SOME_DEFINE
bool flag,
#else
struct exception* ex,
#endif
void* buffer,
size_t size,
)
{
...
}
This code above will lead any project to a total clasterfuck!
Now, how it's supposed to be done.
Abstraction is your friend! The general separation between 3 main things: hardware, platform and compiler / tool chain. Some people mess up compiler and platform.
So, I've created a dummy example of a project and a directory structure should look like this. It should give you a clear idea how the separation is done:
firmware/
├── bin
│ ├── arm
│ ├── windows_x64
│ └── windows_x86
├── build
│ ├── gcc
│ │ └── arm
│ ├── keil5
│ │ └── arm
│ └── vs2017
│ └── windows
├── include
│ └── firmware
│ └── frm.h
├── src
│ ├── arm
│ │ ├── frm_init_impl.c
│ │ └── frm_platform.h
│ ├── frm_idle.c
│ ├── frm_init.c
│ ├── frm_state.c
│ └── windows
│ ├── frm_init_impl.c
│ └── frm_platform.h
└── test
└── firmware_test
├── build
│ └── vs2017
│ └── windows
└── src
1. Write platform in-depended code as much as possible! It will ease development and debugging in most cases. For example, it is much easier and simpler to write & debug as much code as possible in the handy environment like Visual Studio then use vi and gdb or even Keil - which is to my personal opinion is an overpriced piece of garbage!
2. As soon as you have a platform dependent functionality it has to be moved into _impl.c
file and all platform specific definition into _platform.h
file
FrmStatus frm_init()
{
// Platform in-depended code
...
status = frm_init_impl(...);
if(FAILED(status))
{
...
}
// Platform in-depended code
...
}
In this case you will have different implementation of frm_init_impl
function in different folders and files for let's say windows simulation code and real chip specific one. But your platform in-dependent frm_init
function will always stay the same no matter what!
3. Separate compilers and tool chains by using different folders in build
directory. Then those project files include specific .c
and .h
files from corresponding subfolders of src
;
This approach will help you easily develop test suite for your firmware using simulation for windows or emulation for Keil, for example. And then you can create test project for real hardware.
If I missed something I will edit it in the process and developers from the community will help, I guess.
Upvotes: 1