Trouble with #ifdef across multiple files - c

util.h contains the following code:
#ifdef DEBUG
#define LOGGER() MACRO_WRAP(printf("Entering %s\n", __func__))
#else
#define LOGGER() MACRO_WRAP()
#endif
foo.c contains this code:
void foo_start(foo *m)
{
LOGGER();
do_action(m, START);
}
and then foo_unit_tests.c contains calls to foo_start(). I'd like to be able to #define DEBUG at the top of the relevant files -- i.e. I want it to be turned on for unit tests, but not for the main code.
I can't get it to work. Putting #define DEBUG at the top of foo_unit_tests.c doesn't produce the desired behavior. The only way I can get it to work is by putting #define DEBUG either at the top of util.h or foo.c, both of which are much messier than I would like.
What am I missing here? I thought that the macro defined in the .c file would be visible inside of all of the .h files that it included.

You have to have the #define at the beginning of all your files that need that macro defined, or through including a .h file that has it in it.
If you want a cleaner way of doing that, then it is probably better to use the compiler flags to set environmental variables.
For example
icpc -DDEBUG=whatever source.c ...
Or even better, you can enable this compiler flag though an environmental variable in your makefile.

foo_unit_tests.c most likely does not include foo.c, so the #define there is never seen when compiling foo_unit_tests.c

define your normal logger somewhere.. the in the unit test..
#undef LOGGER()
#define LOGGER(x) fprintf(stdout, x)
or alternately you could do something like:
#ifdef UNITTEST
#define LOGGER ...
#else
#define LOGGER ...
#endif
and you pass in the UNITTEST macro from the build env when you build test

Related

Get a warning with #ifndef foo #def foo #warning foo is n defined #endif

EDIT : reformulate my question :
In file like delay.h (for avr programming in embedded system) you find this kind of pre-processor define :
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
# define F_CPU 1000000UL
#endif
It seems quite simple. If nobody defined a value for F_CPU, this will declare 10000000 for it and continue compilation. There is no .c file only a .h file.
Now I have a couple of .c and .h file of my own. And when I try to implement this kind of protection for another value. I get a warning even if I previously declared the value in mu main.c file.
main.c file :
#define BAUDE_RATE_SPEED 115200
#include "uart_ctrl.h"
void main(){
}
uart_ctrl.h file :
#ifndef __UART_CTRL_H__
#define __UART_CTRL_H__
#ifndef BAUDE_RATE_SPEED
#define BAUDE_RATE_SPEED 9600
#warning "BAUDE_RATE_SPEED defined at 9600 in uart_ctrl.h"
#endif
void uart_config();
#endif
uart_ctrl.c file :
#include "uart_ctrl.h"
void uart_config(){
MCU_REGISTER.UART = BAUDE_RATE_SPEED;
}
build error :
Warning #warning "BAUDE_RATE_SPEED defined at 9600 in uart_ctrl.h" [-Wcpp] \uart_ctrl.h Build 1
Why this rise me a warning ? Is it normal and i don't understand behaviours or I missed something ?
Thanks again for your help.
------------- Previous question
Ok, I didn't exactly how to ask this questions. Let me know if you see a better option than the title I set.
On embedded system is very common to declare the mcu frequency with this statement for 20Mhz frequency.
#define F_CPU 20000000UL
And it's common too, to have this kind of check, in files using it. Let say delay.h :
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
# define F_CPU 1000000UL
#endif
If I define F_CPU in my main or anywhere before including my delay.h the warning does not appear and the the first declared F_CPU value is used.
Now I'm writing my own library, I'm trying to do the same, with the same structure. For example :
#ifndef UART_BAUD_SPEED
/* prevent compiler error by supplying a default */
# warning "UART_BAUD_SPEED not defined bla bla"
# define UART_BAUD_SPEED 115200
#endif
But it trig warning anyway. If my library is .H file only or if this is couple h/c file.
How can I implement the same warning/error protection in my library ? What i'm missing ?
Thanks in advance for your help.
The compiler compiles each file separately. When it compiles main.c, main.c defines BAUDE_RATE_SPEED before it includes uart_ctrl.h. When it compiles uart_ctrl.c, nothing defines BAUDE_RATE_SPEED before uart_ctrl.h, so it is not defined and it gives the warning.
When you run the compiler it has an option to define things automatically before compiling the file, which might be where F_CPU comes from. It would be typical to add -DBAUDE_RATE_SPEED=9600 to the compiler command for all files in the project, instead of defining it separately in each file. If you are using an IDE, you may have to figure out where to enter this in the IDE.
Ok, I found where is my miss-understanding.
as #user253751 said, each files is compiled separately. But this only apply to file with couple .h/.c file. Because the delay.h file is header only file, it is never compiler alone. Only included. So the warning never triggered.
Thanks for your help.

CMake : different configure_file() for each target

I'm not very familiar with cmake but as the title says what i'd like to do is the following:
I've an header file of configuration (eg config.h.in), in which I'd like to specify all my parameters depending on which target I'm currently calling. So my header file is something like:
#cmakedefine TEST #TEST#
#cmakedefine PINK #PINK#
#ifndef TEST
#define MY_A 10
#endif
#ifdef PINK
#define MY_A 20
#endif
Now, in my CMakeLists.txt I would like to have multiple targets, so for example (actually the config.hfile is just included from other .c files)
add_executable(FirstTarget
something.c
somethingelse.c
config.h
)
add_executable(SecondTarget
something.c
somethingother.c
config.h
)
And what i would really like to do is that FirstTarget And SecondTarget have different configuration file, so what I'm asking is if it possible to run something like
set(TEST Test)
configure_file(config.h.in config.h)
just for target FirstTarget, and then someway running for SecondTarget
set(PINK Test2)
configure_file(config.h.in config.h)
so that if i call make FirstTarget and make SecondTarget they've different configuration parameters each.
Thanks!
The command configure_file creates a "real" file: it has the same content for each target.
However, the created file may contain #ifdef (or other conditional statements), so its interpretation may differ for different target.
Following example uses target_compile_definitions command for "assign" compile definitions for a specific target.
config.h:
#ifndef TEST
#define MY_A 10
#endif
#ifdef PINK
#define MY_A 20
#endif
CMakeLists.txt:
add_executable(FirstTarget ...)
# When "config.h" will be included into this target, it will use "PINK" branch.
target_compile_definitions(FirstTarget PRIVATE PINK)
add_executable(SecondTarget ...)
# When "config.h" will be included into this target, it will use "TEST" branch.
target_compile_definitions(FirstTarget PRIVATE TEST)

function definition in header file(c using gcc)

I am writing a simple c test framework. For simplicity, I only provide a single header file (containing all the function definitions), but I meet some problems. If I only include the header once, everything works fine. If I include the header twice, the gcc linker report duplicate symbol error (that is normal), so I add static prefix in every function in the header. This time it works, but the function is duplicate in the final binary. See bellow:
[heidong#HEIDONGVM ztest]$ nm m | grep __ct_hex_dump
0000000000400904 t __ct_hex_dump
0000000000401efc t __ct_hex_dump
Is there some way the made the function define only once?
Thanks a lot!!
Maybe someone needs the code, I just started a project in github: https://github.com/buf1024/test
Thanks again!!
What you have is in ct.h
static functions
static function definitions
In atest.c
// This is the first lot of definitions
#include "ct.h"
In main.c
// This is the second lot of definitions
#include "ct.h"
To fix
move the static function definitions to ct.c, remove the word static
Change all the prototypes in ct.h from static to extern
add ct.c to your link.
Edit: just delivering just ct.h
Change all the prototypes in ct.h from static to extern
Before the first function body add #ifdef __CT_C__
After the last function, add #endif
Tell the user that in the code that contains main, they need to #define __CT_C__ before they #include "ct.h"
Anything else that #include "ct.h" must not define __CT_C__.
Use compiler directives.
#IFNDEF MYFUNC
#DEFINE MYFUNC
myfunc();
#ENDIF
Everytime the compiler hits this directive, it will only go in once when MYFUNC is not defined and after defining it, it won't go in the statement again. No matter how many times you include the header file, it will always check if it's been defined before.
Coppiler directives is not part of the compiled code. It's just a directive.
If you absolutely need only one file, you can do it with preprocessor:
header.h
#ifndef HEADER_H
#define HEADER_H
#ifdef IMPLEMENT
#undef IMPLEMENT
void func(void) {
...
}
#else
void func(void);
#endif
#endif
In one file:
// Define
#define IMPLEMENT
#include "header.h"
In other files:
// Only declarations
#include "header.h"
Though I would choose a proper .c file instead.

How to pre-compile a C source file without expand the included header file?

I am working on a large project using C language, which has a lot of preprocessor macros: #ifdef/#if. The macros are defined in makefile.
In order to get the clean code, I modified the makefile to use "gcc -E". But the gcc preprocessor would expand the included header file as well, which I do not expect.
Is there any method to get rid of the #ifdef/#if without expand the included header files? I searched GCC options but not find an answer yet.
An example:
#include "a.h"
#ifdef ABC
func()
#else
func(a)
#endif
{
...
}
In makefile, this source is compiled with -DABC, I am looking for a method to change the file to:
#include "a.h"
func()
{
...
}
If you only want to remove preprocessor conditionals from your code you can use unifdef :
unifdef -DFOO header.h

Write a macro for C/C++ #include

I work on AS/400 which is sometimes non-POSIX. We also need to compile our code on UNIX. We have an issue with something as simple as #include.
On AS/400, we need to write: #include "*LIBL/H/MYLIB"
On UNIX, we need to write #include "MYLIB.H"
At the moment we have this (ugly) block at the top of each C/C++ file:
#ifndef IS_AS400
#include "*LIBL/H/MYLIB"
/* others here */
#else
#include "MYLIB.H"
/* others here */
#endif
We would like a unified macro. Is this possible? I don't know how to write it.
Ideally, the resulting syntax would be: SAFE_INCLUDE("MYLIB") that would expand correctly on each platform.
Please advise.
You can simply #include some separate header in every of your source files containing that ugly #ifndef just once. It's a common practice anyway.
You can define prefixes for your platform as macro. Like
#define STRINGY(STR) #STR
#define SAFE_INCLUDE(HDR) STRINGY(HDR)
#ifndef IS_AS400
#define SAFE_INCLUDE(LIB) STRINGY(*LIBL/H/##LIB)
#else
#define SAFE_INCLUDE(LIB) STRINGY(LIB##.H)
#endif
and you can use this as
#include SAFE_INCLUDE(MYLIB)
There are two better solutions:
Use your Makefiles to properly set a path where compiler looks for includes.
For GCC you add to CFLAGS -I <path> (you can do that multiple times).
Wrap the non-compliant libraries with your own header files.

Resources