Who is this article for?
It is unlikely that experienced C ++ developers will find something new and interesting in this article. Maximum banal team
gcc -c -x c++ -I ./ */*/*/*/*.h
which they already know.
But if you are a beginner developer, or only for the first time build documentation on your project, or try it once, but after seeing that nonsense that generated doxygen, delete it and forget it like a bad dream, welcome to the cat, most likely you will find further a couple of useful thoughts.
Introduction
C ++ programming is primarily an analysis of existing code.
For several years now I have been participating in the development of a simulation system. Development is conducted on the great and mighty ... brainchild of Straustrup. And, I must say, this project has long been written not so much in C ++, as in its own dialect of macros (below it becomes clear why this is important). I think the situation is so familiar to many C ++ developers.
When I first began to study this project, I was immediately advised to build documentation on it using doxygen. But for some reason, friendship with this tool did not work out, and the next time I remembered about it already years later.
Prehistory
As time went on, my professionalism (as I hope) grew, the project developed and I wanted to bring order to the library, which was actively ruled. The order here means the concept of one header file = one entity (or several small and closely related), as well as the division of all files into three types - header, internal and source - respectively, * .h, * .inl, * .cpp. Moreover, the separation should take place in such a way that the header files do not contain a single member function definition of the class, and all of them are either in cpp-files or inl-files. In addition, all module code had to be formatted according to a single standard, and, most interestingly, most entities had to be commented out using special doxygen commands (\ interface, \ class, \ todo, \ brief, \ enum, etc.) .
')
Problem
No sooner said than done. After about a few weeks of killed evenings, an insane task is completed! The code is beautiful so that a little tear does not turn around.
And it is time to lie back in a chair, waiting for doxygen to build me the most beautiful and correct documentation describing my (at that time already the most beloved) module of the system. And with a sinking heart
cd Project/doc
doxygen project-doxyfile
cd html/
./index.html
However, what appeared to my gaze was, to put it mildly, garbage. Doxygen frankly shalturil: diagrams are incomplete, namespace 'is empty, macros are trying to give me functions, in general, I cannot count everything ... But the primary analysis showed that he did not understand macros (all namespaces, smart pointers (own production, by the way) and many the other was set using macros).
Solution in option PREDEFINED?
First of all, doxygen settings were under suspicion. Such options as ENABLE_PREPROCESSING, MACRO_EXPANSION, EXPAND_ONLY_PREDEF, SEARCH_INCLUDES and INCLUDE_PATH were re-checked. But the settings looked logical, and the macros were not perceived correctly. Then the PREDEFINED option was used, although she didn’t answer the question “why do oxygen foul?”, But allowed him to explain the necessary macros. This was the solution to the problem for a while. But the fact that it was necessary to constantly add new macros to this option was very depressing and forced to continue studying doxygen.
The problem is in the code!
For a long time I thought about the behavior of doxygen and googled. And once he even leaked it to himself by svn with the righteous thought of finding and fixing a terrible bug preventing him from processing macros :)
But I stopped in time, because I understood what made it different from the compiler. They have very different goals (and in doxigen, in some ways, it is even more difficult), because it needs not only to understand cpp-files, but to do the same with header files, in order to show it beautifully to the user, i.e. by file And here comes something interesting, which I haven’t thought about before: the compiler is not interested in header files, it receives a “translation unit”, or a preprocessor output with already processed #include directives. Let me rephrase it in this way - the compatrirator deals with header files only indirectly, so to speak, in the context of a translation unit. And compiles it in this very context. This leads to a disappointing conclusion - the header file may be wrong on its own, but becomes correct in the context of its use, and the compiler will not tell you anything about it!
But with doxygen, this does not work - the header file is analyzed as an independent, self-contained document with source code. And if it lacks declarations of the entities used (which appear in the context of using this header file), then doxygen will be wrong. And it seems that this disease has befallen our project.
So what kind of error, elusive for the compiler, is hidden in the header file? These are not #include the directives of the files where the notorious macros were defined. Those. when compiling cpp-files, all definitions fell into the current translation unit in some workaround, and not through the “problem” header file. After this discovery in our team, a meeting was held, with the main issue on the agenda “and what to do with this, strictly speaking?”. The question was resolved in favor of the fact that such behavior — the absence of all the necessary inclusions — was a mistake. The basic argument is quite simple - the header file can potentially be included anywhere, and therefore must be so self-sufficient to compile.
Solution - “compile header files”
This is where the issue of “compiling header files” became.
The meaning of this event is to force the compiler to analyze all header files without putting them into the context of the source (* .cpp) files, and report errors. And then, if they are fixed, then doxygen should not have any excuses left to correctly construct the project documentation with all the diagrams and stuff.
Now it's time to talk directly about the compiler used in our team.
For historical reasons, this is ms visual studio, the standard of 2008 already. But just before the final of this story, the project of converting the computational kernel of the system to GNU / Linux was successfully completed. And naturally, in this environment, was chosen as the GCC compiler, version 4.6.
And I began to torment him with requests I supposedly compile me the headlines. And he resisted for a long time ... until he bent.
A thoughtful reading of his man indicated to me the -I option, with which GCC can indicate the path from which to find inclusions in quotes.
One important fact should be noted here, in our project we have long (and quite successfully) adhered to the rule “specify the path to the file in the project from the project root”. This discipline allowed to do the only option -I.
Then it remains to submit to the gcc input all the header files of the project. But here there was some hitch associated with the reluctance of gcc to accept the output of the ls command through the pipeline at the input. But the solution turned out to be even more trivial, gcc and so carried out the search for input files by the transferred mask.
So the team
g++ -I ./ */*/*/*/*.h */*/*/*.h */*/*.h
fully validates all library header files.
The next time gcc began to resist, if you give it the input * .inl files. The options -c (compilation without linking only), and -x c ++ (explicit programming language set) helped.
The final command used to validate the header (* .inl files we decided to leave alone) files:
gcc -c -x c++ -I ./ */*/*/*/*.h */*/*/*.h */*/*.h
Well, it remains to correct the errors and use doxygen.
And, in general, still, for sure, something can be improved, for example, to screw cmake here, but the main idea of ​​this post is precisely the need to “compile header files” to counter the seemingly strange behavior of doxygen. So I’ll stop on this until I tired the last most diligent reader;)
Instead of conclusions
And actually, why the post is called "... or documentation for freebies."
Yes, just in the code there may not be a single line of doxygen comment, but you can still build documentation on it with all sorts of diagrams, which can help a lot when learning a new project. Namely, the automatic construction of documentation (with convenient navigation and charts) should have made it easier for new students (and all this happens in a technical college) to study a very large and complex system and was the original goal of using doxygen in our project.
Naturally, in the comments I look forward to constructive criticism, corrections, additions to my moderately curved commands and questions.