Reputation: 132108
I have a C file (for simplicity, assume it includes nothing). This C files requires several definitions of literal numbers to compile properly - and I want to figure out which definitions these are.
Naturally, one can try to compile the file, and at some point we would start to get failures; with some failure recovery, we might get failure notifications about additional defines. But - that's not what I want:
[A-Z][A-Z_0-9]*
).What are my alternatives for getting the list of undefined macros?
Motivation: In reality, I'm feeding something into a dynamic compilation library, and I want to check beforehand if all necessary macros have been defined, without knowing a priori which macros the file needs (i.e. it could be different ones for different input files).
Upvotes: 1
Views: 52
Reputation: 16057
You could use something around the idea that every identifier-like non-keyword outside a comment in a C file must be declared somewhere. (I think! Is that correct?)
The basic idea is to generate a list of such identifiers and search the program and then the included headers for a declaration of each. While this can be done by hand and ad-hoc it probably makes sense to index all potential header files and to use something like ctags for indexing as well as finding (there is a libctags, as I just learned).
I assume that the solution doesn't have to be perfect — missed cases will simply fail compilation — but that you want to reduce such cases. In that case the parsing of the source code for identifiers does not have to be perfect (it can ignore nested comments etc.) and can probably be done "manually" with acceptable effort.
Upvotes: 0
Reputation: 132108
Obviously, your fallback is to just compile the program. But - do so while minimizing irrelevant messages and irrelevant. This will be compiler-dependent, but with GCC for example, you can:
... using various command-line switches and when making it take input from the standard input stream rather than a file (only way I've found so far to suppress some of the notes). That looks like:
cat your_program.c \
| LC_CTYPE=C gcc -std=c99 -fsyntax-only -x c -fcompare-debug-second -
and the output could look like:
<stdin>: In function 'mult':
<stdin>:3:18: error: 'MY_CONSTANT' undeclared (first use in this function)
Now, if your program is correct other than the undefined macros (= undeclared identifiers), then you can easily parse the above with a bit of shell scripting:
cat your_program.c \
| LC_CTYPE=C gcc -std=c99 -fsyntax-only -x c -fcompare-debug-second - \
| sed -r '/error: /!d; s/^.*error: '"'//; s/'.*//;" \
| sort -u
This has the further disadvantage of not being fully embeddable into your program, i.e. you can't invoke the partial compilation using some library in some program of yours, then programmatically parse the output. You would need a system()
-type call.
Note: If your program can have other errors, the pattern for dropping the line in the sed
command will need to be a little more specific.
Upvotes: 1