tags:

views:

169

answers:

6

I would like to be able to get a list of all possible files included in a C source file.

I understand there are complications with other # directives (for instance, an #ifdef could either prevent an include or cause an extra include). All I'm looking for is a list of files that may have been included.

Is there a tool that already does this?

The files I'm compiling are only going to .o, and the standard C libraries are not included. I know that sounds wonky, but we have our reasons.

The reason I want to be able to do this is I want to have a list of files which may have contributed something to the .o, so I can check to see if they have changed.

+1  A: 

You could do the preprocessor step only. Most compilers allow this.

Of course that would require some busywork reading the resulting file.

John Weldon
+1  A: 

All POSSIBLE files? No way to do that.

McWafflestix
I think he means "All files that would be included if conditional directives were stripped out." Not "Any file that could have been included if I'd decided to write an #include line for them."
Chuck
+2  A: 

my syntax is rusty, but ...

grep -ir "#include " *.c

might work ...

Adrien
+2  A: 

If you use gcc you can inspect preprocessor dump:

[~]> gcc -E /usr/include/cups/dir.h|grep "#"
# 1 "/usr/include/cups/dir.h"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "/usr/include/cups/dir.h"
# 26 "/usr/include/cups/dir.h"
# 1 "/usr/include/sys/stat.h" 1 3 4
# 73 "/usr/include/sys/stat.h" 3 4
# 1 "/usr/include/sys/_types.h" 1 3 4
# 32 "/usr/include/sys/_types.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 33 "/usr/include/sys/_types.h" 2 3 4
# 1 "/usr/include/machine/_types.h" 1 3 4
# 34 "/usr/include/machine/_types.h" 3 4
# 1 "/usr/include/i386/_types.h" 1 3 4
# 37 "/usr/include/i386/_types.h" 3 4
# 70 "/usr/include/i386/_types.h" 3 4
# 35 "/usr/include/machine/_types.h" 2 3 4
# 34 "/usr/include/sys/_types.h" 2 3 4
# 58 "/usr/include/sys/_types.h" 3 4
# 94 "/usr/include/sys/_types.h" 3 4
# 74 "/usr/include/sys/stat.h" 2 3 4
# 1 "/usr/include/sys/_structs.h" 1 3 4
# 88 "/usr/include/sys/_structs.h" 3 4
# 79 "/usr/include/sys/stat.h" 2 3 4
# 152 "/usr/include/sys/stat.h" 3 4
# 228 "/usr/include/sys/stat.h" 3 4
# 248 "/usr/include/sys/stat.h" 3 4
# 422 "/usr/include/sys/stat.h" 3 4
# 27 "/usr/include/cups/dir.h" 2
# 42 "/usr/include/cups/dir.h"
cartman
The problem with the preprocessor dump is that it shows you what was included for that particular invocation of gcc; it will not show that, if you had defined "magic" on the command line, an entirely different set of files would have been included.
Thomas L Holaday
+10  A: 

Quoting the man page for gcc:

-M  Instead of outputting the result of preprocessing, output a rule
    suitable for make describing the dependencies of the main source
    file.  The preprocessor outputs one make rule containing the object
    file name for that source file, a colon, and the names of all the
    included files, including those coming from -include or -imacros
    command line options.

This basically does what you want. There are several other related options (all starting with -M) that give you different variants of this output.

sth
Thanks! Is there a way to do this such that all #include lines count, even if a #ifdef would remove it?
Chris
If you want everything that stands inside an #include, no matter if it's actually included or not, you're probably best going with "grep".
sth
Using grep to search for all -P '\#include ".*" would be easy enough, but that wouldn't handle included files that themselves have included. To handle this, the 'one liner' seems like it would get fairly complicated.
Chris
You could make a copy of you source tree, remove all #(if|else|end) lines and then process the result with gcc -MG...
sth
+2  A: 

Alas, simply grepping the source for #include is not guaranteed to be enough, because someone may have committed ...

#define tricksy(foo,bar) <foo##bar>
#define precious tricksy(ios, tream)
#include precious
int main(int, char **)
{
        std::cout << "Hobbits!" << std::endl;
        return 0;
}

... though you would be able to tell by inspection that something nonstandard was going on with the #include precious because of the missing <> or "".

A non-perverse example would be token-pasting different library root directories depending on command-line definitions.

Thomas L Holaday
This could be a problem for the general solution to my question, but I'm sure no one was crazy enough to do something like that with the source I'm working on. The problem with grepping the source is that I want to know all files included, even those included from includes.
Chris
+1 for identifying a possible even if only lightly plausible edge case. Although, I have this temptation to use a trick like this now...
RBerteig