14

Say I use some C or C++ library, made out of headers and some source files, that are compiled into a static or shared library I can link with.

In the headers of the library (dozens... or hundreds of files), some macros/symbols are defined.

Now I want to use this library in a project, that also defines some macros and symbols. Of course, I want to avoid name collisions, as this has been reported sometimes, particularly with windows.h. But more generally I want to keep control of what is really exported out of that header.

I can produce a list of defined symbols with gcc preprocessor options:

gcc -E -dM include/great_lib.h | sort -V >symbols.txt

This outputs in file symbols.txt a sorted list of all the defined symbols included in a user file when it includes this header.

However, it only gives the symbol, not the file where it was defined.

I have the feeling that this could be a useful information. For example, to check if some system macro is being redefined in "great_lib.h" or its ascendants. Unfortunalty, after checking gcc preprocessor options, I don't see a way to do that using gcc.

For example, instead of only giving me:

#define M_PI 3.14159265358979323846

it would produce

#define M_PI 3.14159265358979323846; /usr/include/math.h

Maybe something with the -dN option ? But its output is confusing for me, it requires further text processing, and I don't understand how the information is layered. Or a simpler way ?

Related questions:

Community
  • 1
  • 1
kebs
  • 6,387
  • 4
  • 41
  • 70

3 Answers3

2

The -dD option outputs the preprocessed source along with the macros. This includes lines that indicate the current source file, e.g.

# 1 "c:\\mingw\\bin\\../lib/gcc/mingw32/4.5.2/../../../../include/_mingw.h" 1 3

You can write a little program that (i) keeps track of the current source file by parsing these lines; (ii) outputs all lines that start with #define (and \t# define etc.), followed by the current source filename; (iii) discards all other lines (the source code, declarations etc.).

TonyK
  • 16,761
  • 4
  • 37
  • 72
  • This is similar to the -dN option, it does indeed hold the requested information, in some odd order. Is this output format documented somewhere ? I mean, I get lines like this: http://pastebin.com/gFXTH2rB, blank line included, and it is not obvious what these numbers mean. Unless I failed, GCC doc (see link in question) isn't very verbose about it. – kebs Jan 12 '13 at 17:28
  • Oops, sorry, it is actually pretty well documented (http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html), I'll check that. – kebs Jan 12 '13 at 17:40
1

A quick unix way to do it:

find "$PATH_TO_LIB" -name "*.h" | xargs grep "^[ \t]*#[ \t]*define"

You could then use sed and sort to clean up the formatting a bit.

Also, according to the gcc manual, gcc will warn you about this sort of thing.

http://gcc.gnu.org/onlinedocs/cpp/Undefining-and-Redefining-Macros.html

If a macro is redefined with a definition that is not effectively the same as the old one, the preprocessor issues a warning and changes the macro to use the new definition. If the new definition is effectively the same, the redefinition is silently ignored. This allows, for instance, two different headers to define a common macro. The preprocessor will only complain if the definitions do not match.

jmh
  • 8,856
  • 1
  • 18
  • 26
  • That will miss a lot of defines. The search pattern should be `^[ \t]*#[ \t]*define`. – James Kanze Jan 11 '13 at 15:21
  • 1
    Mmh, nice start, but this parses all the headers of the folder, not only the ones that are really included by the "main" header file. So I also get symbols that are not propagated in user code. The gcc way does intelligent parsing, showing you only the exported symbols. – kebs Jan 11 '13 at 17:14
  • Perhaps use the output of `gcc`'s `-M` option? Or incorporate the `grep`ing in the `Makefile`? – alk Jan 11 '13 at 18:57
  • @alk: well that will only show the files included **directly** in the considered header, not those that are included indirectly. Sure, I can fetch those recursively, but it is starting to get non-trivial at all. – kebs Jan 12 '13 at 16:55
  • About your edit: the question is not so much to check potential redefinitions of macros than to control what macro names are actually exported into user code. But that's a +1 anyway ;-) – kebs Jan 12 '13 at 17:37
  • 1
    that variant is really *BAD*. it will find defines however it does not tell you which defines the compiler by itself sets. – Alexander Oh Apr 25 '13 at 13:17
  • The quick Unix way is `ctags *.h`. – Jens Apr 23 '16 at 20:22
1

Don't reinvent the wheel, clumsily. All that gcc -dM stuff gives you a square wheel :-)

Any ctags (for vi) or etags (for emacs) program will extract that information (which identifier is defined/declared in which file). As a bonus, you'll have it in a form that is directly understood by editors, allowing you to place the cursor on an identifier and then jump to its declaration/definition.

Use the tools in the toolbox, use the Unix philosophy of having one tool do one thing well.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • This square wheel might ride very poorly, i.e. it is not doing it's job well. Imagine you have a large codebase where the same symbol is defined in dozens of headers which are imported differently to dozens of different configurations of the same codebase and you are debugging which particular header this particular symbol comes from to do further analysis/fixes on other symbols pulled from the same header. – Blackhex Jul 04 '23 at 08:12