Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How to partially pre-process a file, without expanding #include or #embed ?
I'm debugging some "clever" macros (similar to, but not exactly the same as, X macros https://software.codidact.com/posts/293492 ).
Is there a way to get a compiler or a preprocessor (such as gcc or cpp or gpp) to expand only "short" macros and leave "long" preprocessor stuff alone? so if I have something like
#include <enormous_library>
#include <some_other_library>
#embed "embedded_literals.txt"
int main(void){
set_baud_rate(baud_rate)
}
and one of those libraries mentions
#define baud_rate 1200
I want to somehow generate a (relatively short) partially-preprocessed file something like
#include <enormous_library>
#include <some_other_library>
#embed "embedded_literals.txt"
int main(void){
set_baud_rate(1200)
}
The
gcc -save-temps
option tells gcc to expand all the preprocessor stuff into an enormous file with a copy of all the libraries and embedded literals, which can make what I'm looking for hard to find.
1 answer
If your goal is just to temporarily see what a file looks like without certain headers, and the headers themselves do not depend on each other, then you can either temporarily comment them out, or declare a "guard" macro for them
Let me explain header "guards"
When creating a header file, these lines are almost always written:
#ifndef _LIB_NAME_H
#define _LIB_NAME_H
#endif /* _LIB_NAME_H */
They provide protection against including the same header twice
Example:
There is another header:
#ifndef _LIB_2_H
#define _LIB_2_H
/* some code here */
#include "lib_name.h"
#endif /* _LIB_2_H */
And in the main file we do:
#include "lib_name.h"
#include "lib_2.h"
/* ... */
If in lib_name.h we had, for example, typedef int some_t and there were no guards,
then we would define the same some_t twice, which is already an error
So we check whether the macro is defined - "has this header already been included?"
If not, we provide the code and define the macro, so the next time the code will not be inserted again
This is implemented by using #ifndef directive (if not defined)
In this case, this can be used to trick headers into thinking they were already included
To do this, we need to define the macros of the headers we don't need before including them
In principle, the macro name can be anything, but a common convention is:
_HEADER_NAME_H
It starts with _, then the header name in uppercase, and at the end .h is replaced with _H (if the file has that extension)
You can define these macros either before including the unwanted headers:
#define _ENORMOUS_LIBRARY
#include <enormous_library> /* This library will be ignored */
#include <some_other_library>
#embed "embedded_literals.txt"
int main(void){
set_baud_rate(baud_rate)
}
Or directly when running the command:
$ gcc -D_ENORMOUS_LIBRARY file.c
-D defines a macro
Speaking of #embed, honestly, I don’t know what this directive does
Nevertheless, you can write a similar "wrapper" so that this directive is either executed or not:
#ifndef DO_NOT_EMBED_LITERALS
#embed "embedded_literals.txt"
#endif /* DO_NOT_EMBED_LITERALS */
Here we again use #ifndef, i.e. we check that such a macro is NOT defined
If we define DO_NOT_EMBED_LITERALS before this check,
then the #embed directive will not be executed
This can be done either by defining it in the code, or by defining it via a command:
$ gcc -DDO_NOT_EMBED_LITERALS file.c

1 comment thread