I am using a third party open source project and need to strip out the inactive #ifs, #ifdefs, etc to better understand the code flow.
Is there a way to use make to produce versions of the source files without these directives? I'd like to avoid expanding macros, just remove directives.
I was looking at https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html
and it seems like -dD and -fdirectives-only are good options to start.
Where will these preprocessed files appear? Where do I add these commands for use with a Makefile and "make"? I tried running "make -n" to produce a script and adding options to the g++ and gcc calls in the script after -Wformat among other things, but I dont notice anything.
I'm not sure if this complicates anything, but I am also using avr-gcc and avr-g++.
I have looked at coan, which does not support #included #defines so it would not work for this purpose, and I could not get sunifdef to work. Is there is a way of doing this with the preprocessor.
The defines are scattered among the current file, the included files, and included makefiles that specify -Dfoo=opt options.
You're on the right track with your preprocessor options. -D will define a macro with a value of 1, -U will cancel any previous definition (it will become undefined), and -fdirectives-only will suppress macro expansion. In addition to those, you can use the -E flag with gcc to tell it to provide the preprocessor output as separate files for your examination. However, I don't think they're going to be quite what you expect. The CPP (C pre-processor) output may have other things added to it, as suggested by this SO question, and you should check the gnu CPP output manual page. That is what you will get from the CPP.
It sounds like you want to be able to strip this extraneous code once and develop from there. To do that, I would encourage you to give unifdef another try. This is what unifdef was designed to do, while the CPP was designed to prepare code for compilation. They're different tasks, so you should use the right tools for them. It is available as a standalone application at http://dotat.at/prog/unifdef/ and is built into some Linux Shells.
It allows you to specify macros that you want it to consider defined or undefined, and it removes blocks of code where the conditional directive would evaluate to false. For example, you can run it like this:
unifdef -I< path > -DMACRO1 -UMACRO2
It will search through the directory specified by < path > through C/C++ source files, looking for #if
, #ifdef
, #ifndef
, etc. When it encounters them, it will evaluate the conditional expression and selectively remove the code controlled by that expression. Consider an input file with this code:
int i = 0;
#ifdef MACRO1
int j = 0;
#endif /* ifdef MACRO1 */
int k = 0;
int m = 0;
#if (MACRO1 && MACRO2)
int n = 0;
#endif /* if (MACRO1 && MACRO2) */
int p = 0;
int q = 0;
#ifdef MACRO3
int r = 0;
#endif /* ifdef MACRO3 */
int t = 0;
If we call unifdef like my example above, the output will be this:
int i = 0;
int j = 0;
int k = 0;
int m = 0;
int p = 0;
int q = 0;
#ifdef MACRO3
int r = 0;
#endif /* ifdef MACRO3 */
int t = 0;
Notice that the declaration of n has been removed, because it was contained in a preprocessor #if
/#endif
block whose controlling expression evaluated to false (we told unifdef to consider MACRO2 undefined). The declaration of j remains, but the #ifdef
and #endif
statements were removed because the controlling expression was known to be true.
The block that depends on MACRO3 is left untouched because its state is unknown.
There is a significant amount of flexibility and control over how this runs, too.
If you decided you do want it to be part of your build process, you can always add it to your makefile.
If you do not have a list of which macros should be defined or undefined available, you can use the "unifdefall" script provided with unifdef and it will use the CPP to discover macro definitions in the source code on its own, and remove/keep code blocks according to the definitions contained in the source code.
Yes you can (sort of) do it with the preprocessor. But unifdef and sunifdef are tools that are made to do exactly this, so you should use them instead.
Assumptions
My strategy is to use a program like unifdef. The first time I did this I wrote my own, and you may have to modify the program to produce the desired results.
The core strategy is:
One symbol at a time, testing thoroughly every time. Some symbols may turn out to be too hard, and if you have much more than a million lines of source code and a hundred or so symbols it can all get out of hand.
Final step: if you modify unifdef then feel free to contribute your changes back to the community. This is a seriously challenging task to do well!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With