I need to expand a single preprocessor directive, for example:
Having a source file and two headers, I want to expand only one define
from one specific header, leaving all other include
and define
intact.
The main idea is that, given code similar to this:
defs.h:
#define FOO(X,op) int X(int a,int b) { return a op b; }
other_file.h:
#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5
main.c:
"file: main.c "
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
I would have the main.c output with the same includes, but with FOO expanded to the created functions. I known the example is silly, but I intend to run it on a larger code database.
The motivation to do it is to run cccc in functions that are defined within macros. The easiest way to run it is to expand those macros. I also welcome alternative ways to do this.
You can play with the -E
, -nostdinc
, -nostdinc++
and -fpreprocessed
parameters of GCC.
For your example, you can run:
gcc -E -nostdinc -fpreprocessed main.c
And the output would be:
# 1 "main.c"
#include <stdio.h>
#include "defs.h"
#include "other_file.h"
FOO(add,+)
FOO(sub,-)
FOO(mul,*)
FOO(div,/)
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
If the headers are not that complex, like in your example, you can force gcc to preprocess the whole file even with some missing macros. E.g.:
cp other_file.h other_file.h_orig
echo "" > other_file.h
gcc -E -nostdinc main.c
Output:
# 1 "main.c"
# 1 "<command-line>"
# 1 "main.c"
main.c:1:19: error: no include path in which to search for stdio.h
#include <stdio.h>
^
# 1 "defs.h" 1
# 3 "main.c" 2
# 1 "other_file.h" 1
# 4 "main.c" 2
int add(int a,int b) { return a + b; }
int sub(int a,int b) { return a - b; }
int mul(int a,int b) { return a * b; }
int div(int a,int b) { return a / b; }
int main()
{
printf("%d\n",add(ONE,TWO));
printf("%d\n",sub(THREE,FOUR));
printf("%d\n",mul(FIVE,FIVE));
printf("%d\n",div(25,FIVE));
return 0;
}
It will remove the header inclusions, though... and will print you an error on std headers, that goes to stderr instead of stdout.
This works for your small example, but on larger codebase you may face some problems...
Here is a brief summary of the parameters from the manual (of GCC 4.8.2) :
-E: Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.
-fpreprocessed: Indicate to the preprocessor that the input file has already been preprocessed. This suppresses things like macro expansion, trigraph conversion, escaped newline splicing, and processing of most directives.
-nostdinc: Do not search the standard system directories for header files. Only the directories you have specified with -I options.
-nostdinc++: Do not search for header files in the standard directories specific to C++, but do still search the other standard directories.