Blame doc/arch.doc

Packit Service 50c9f2
/******************************************************************************
Packit Service 50c9f2
 *
Packit Service 50c9f2
 * 
Packit Service 50c9f2
 *
Packit Service 50c9f2
 * Copyright (C) 1997-2015 by Dimitri van Heesch.
Packit Service 50c9f2
 *
Packit Service 50c9f2
 * Permission to use, copy, modify, and distribute this software and its
Packit Service 50c9f2
 * documentation under the terms of the GNU General Public License is hereby 
Packit Service 50c9f2
 * granted. No representations are made about the suitability of this software 
Packit Service 50c9f2
 * for any purpose. It is provided "as is" without express or implied warranty.
Packit Service 50c9f2
 * See the GNU General Public License for more details.
Packit Service 50c9f2
 *
Packit Service 50c9f2
 * Documents produced by Doxygen are derivative works derived from the
Packit Service 50c9f2
 * input used in their production; they are not affected by this license.
Packit Service 50c9f2
 *
Packit Service 50c9f2
 */
Packit Service 50c9f2
/*! \page arch Doxygen's Internals
Packit Service 50c9f2
Packit Service 50c9f2

Doxygen's internals

Packit Service 50c9f2
Packit Service 50c9f2
Note that this section is still under construction!
Packit Service 50c9f2
Packit Service 50c9f2
The following picture shows how source files are processed by doxygen.
Packit Service 50c9f2
Packit Service 50c9f2
\image html archoverview.gif "Data flow overview"
Packit Service 50c9f2
\image latex archoverview.eps "Data flow overview" width=14cm
Packit Service 50c9f2
Packit Service 50c9f2
The following sections explain the steps above in more detail.
Packit Service 50c9f2
Packit Service 50c9f2

Config parser

Packit Service 50c9f2
Packit Service 50c9f2
The configuration file that controls the settings of a project is parsed
Packit Service 50c9f2
and the settings are stored in the singleton class \c Config 
Packit Service 50c9f2
in src/config.h. The parser itself is written using \c flex 
Packit Service 50c9f2
and can be found in src/config.l. This parser is also used 
Packit Service 50c9f2
directly by \c doxywizard, so it is put in a separate library.
Packit Service 50c9f2
Packit Service 50c9f2
Each configuration option has one of 5 possible types: \c String, 
Packit Service 50c9f2
\c List, \c Enum, \c Int, or \c Bool. The values of these options are
Packit Service 50c9f2
available through the global functions \c Config_getXXX(), where \c XXX is the
Packit Service 50c9f2
type of the option. The argument of these function is a string naming
Packit Service 50c9f2
the option as it appears in the configuration file. For instance: 
Packit Service 50c9f2
\c Config_getBool("GENERATE_TESTLIST") returns a reference to a boolean
Packit Service 50c9f2
value that is \c TRUE if the test list was enabled in the config file. 
Packit Service 50c9f2
Packit Service 50c9f2
The function \c readConfiguration() in \c src/doxygen.cpp 
Packit Service 50c9f2
reads the command line options and then calls the configuration parser.
Packit Service 50c9f2
Packit Service 50c9f2

C Preprocessor

Packit Service 50c9f2
Packit Service 50c9f2
The input files mentioned in the config file are (by default) fed to the
Packit Service 50c9f2
C Preprocessor (after being piped through a user defined filter if available).
Packit Service 50c9f2
Packit Service 50c9f2
The way the preprocessor works differs somewhat from a standard C Preprocessor.
Packit Service 50c9f2
By default it does not do macro expansion, although it can be configured to
Packit Service 50c9f2
expand all macros. Typical usage is to only expand a user specified set
Packit Service 50c9f2
of macros. This is to allow macro names to appear in the type of 
Packit Service 50c9f2
function parameters for instance.
Packit Service 50c9f2
Packit Service 50c9f2
Another difference is that the preprocessor parses, but not actually includes 
Packit Service 50c9f2
code when it encounters a \c \#include (with the exception of \c \#include
Packit Service 50c9f2
found inside { ... } blocks). The reasons behind this deviation from 
Packit Service 50c9f2
the standard is to prevent feeding multiple definitions of the 
Packit Service 50c9f2
same functions/classes to doxygen's parser. If all source files would 
Packit Service 50c9f2
include a common header file for instance, the class and type 
Packit Service 50c9f2
definitions (and their documentation) would be present in each 
Packit Service 50c9f2
translation unit. 
Packit Service 50c9f2
Packit Service 50c9f2
The preprocessor is written using \c flex and can be found in
Packit Service 50c9f2
\c src/pre.l. For condition blocks (\c \#if) evaluation of constant expressions 
Packit Service 50c9f2
is needed. For this a \c yacc based parser is used, which can be found 
Packit Service 50c9f2
in \c src/constexp.y and \c src/constexp.l.
Packit Service 50c9f2
Packit Service 50c9f2
The preprocessor is invoked for each file using the \c preprocessFile() 
Packit Service 50c9f2
function declared in \c src/pre.h, and will append the preprocessed result 
Packit Service 50c9f2
to a character buffer. The format of the character buffer is
Packit Service 50c9f2
Packit Service 50c9f2
\verbatim
Packit Service 50c9f2
0x06 file name 1 
Packit Service 50c9f2
0x06 preprocessed contents of file 1
Packit Service 50c9f2
...
Packit Service 50c9f2
0x06 file name n
Packit Service 50c9f2
0x06 preprocessed contents of file n
Packit Service 50c9f2
\endverbatim
Packit Service 50c9f2
Packit Service 50c9f2

Language parser

Packit Service 50c9f2
Packit Service 50c9f2
The preprocessed input buffer is fed to the language parser, which is 
Packit Service 50c9f2
implemented as a big state machine using \c flex. It can be found 
Packit Service 50c9f2
in the file \c src/scanner.l. There is one parser for all 
Packit Service 50c9f2
languages (C/C++/Java/IDL). The state variables \c insideIDL 
Packit Service 50c9f2
and \c insideJava are uses at some places for language specific choices. 
Packit Service 50c9f2
Packit Service 50c9f2
The task of the parser is to convert the input buffer into a tree of entries 
Packit Service 50c9f2
(basically an abstract syntax tree). An entry is defined in \c src/entry.h 
Packit Service 50c9f2
and is a blob of loosely structured information. The most important field 
Packit Service 50c9f2
is \c section which specifies the kind of information contained in the entry.
Packit Service 50c9f2
 
Packit Service 50c9f2
Possible improvements for future versions:
Packit Service 50c9f2
 - Use one scanner/parser per language instead of one big scanner.
Packit Service 50c9f2
 - Move the first pass parsing of documentation blocks to a separate module.
Packit Service 50c9f2
 - Parse defines (these are currently gathered by the preprocessor, and
Packit Service 50c9f2
   ignored by the language parser).
Packit Service 50c9f2
Packit Service 50c9f2

Data organizer

Packit Service 50c9f2
Packit Service 50c9f2
This step consists of many smaller steps, that build 
Packit Service 50c9f2
dictionaries of the extracted classes, files, namespaces, 
Packit Service 50c9f2
variables, functions, packages, pages, and groups. Besides building
Packit Service 50c9f2
dictionaries, during this step relations (such as inheritance relations),
Packit Service 50c9f2
between the extracted entities are computed.
Packit Service 50c9f2
Packit Service 50c9f2
Each step has a function defined in \c src/doxygen.cpp, which operates
Packit Service 50c9f2
on the tree of entries, built during language parsing. Look at the
Packit Service 50c9f2
"Gathering information" part of \c parseInput() for details.
Packit Service 50c9f2
Packit Service 50c9f2
The result of this step is a number of dictionaries, which can be
Packit Service 50c9f2
found in the doxygen "namespace" defined in \c src/doxygen.h. Most
Packit Service 50c9f2
elements of these dictionaries are derived from the class \c Definition;
Packit Service 50c9f2
The class \c MemberDef, for instance, holds all information for a member. 
Packit Service 50c9f2
An instance of such a class can be part of a file ( class \c FileDef ), 
Packit Service 50c9f2
a class ( class \c ClassDef ), a namespace ( class \c NamespaceDef ), 
Packit Service 50c9f2
a group ( class \c GroupDef ), or a Java package ( class \c PackageDef ).
Packit Service 50c9f2
Packit Service 50c9f2

Tag file parser

Packit Service 50c9f2
Packit Service 50c9f2
If tag files are specified in the configuration file, these are parsed
Packit Service 50c9f2
by a SAX based XML parser, which can be found in \c src/tagreader.cpp. 
Packit Service 50c9f2
The result of parsing a tag file is the insertion of \c Entry objects in the
Packit Service 50c9f2
entry tree. The field \c Entry::tagInfo is used to mark the entry as
Packit Service 50c9f2
external, and holds information about the tag file.
Packit Service 50c9f2
Packit Service 50c9f2

Documentation parser

Packit Service 50c9f2
Packit Service 50c9f2
Special comment blocks are stored as strings in the entities that they
Packit Service 50c9f2
document. There is a string for the brief description and a string
Packit Service 50c9f2
for the detailed description. The documentation parser reads these
Packit Service 50c9f2
strings and executes the commands it finds in it (this is the second pass
Packit Service 50c9f2
in parsing the documentation). It writes the result directly to the output 
Packit Service 50c9f2
generators.
Packit Service 50c9f2
Packit Service 50c9f2
The parser is written in C++ and can be found in src/docparser.cpp. The
Packit Service 50c9f2
tokens that are eaten by the parser come from src/doctokenizer.l.
Packit Service 50c9f2
Code fragments found in the comment blocks are passed on to the source parser.
Packit Service 50c9f2
Packit Service 50c9f2
The main entry point for the documentation parser is \c validatingParseDoc()
Packit Service 50c9f2
declared in \c src/docparser.h.  For simple texts with special 
Packit Service 50c9f2
commands \c validatingParseText() is used.
Packit Service 50c9f2
Packit Service 50c9f2

Source parser

Packit Service 50c9f2
Packit Service 50c9f2
If source browsing is enabled or if code fragments are encountered in the
Packit Service 50c9f2
documentation, the source parser is invoked.
Packit Service 50c9f2
Packit Service 50c9f2
The code parser tries to cross-reference to source code it parses with
Packit Service 50c9f2
documented entities. It also does syntax highlighting of the sources. The
Packit Service 50c9f2
output is directly written to the output generators.
Packit Service 50c9f2
Packit Service 50c9f2
The main entry point for the code parser is \c parseCode() 
Packit Service 50c9f2
declared in \c src/code.h.
Packit Service 50c9f2
Packit Service 50c9f2

Output generators

Packit Service 50c9f2
Packit Service 50c9f2
After data is gathered and cross-referenced, doxygen generates 
Packit Service 50c9f2
output in various formats. For this it uses the methods provided by 
Packit Service 50c9f2
the abstract class \c OutputGenerator. In order to generate output
Packit Service 50c9f2
for multiple formats at once, the methods of \c OutputList are called
Packit Service 50c9f2
instead. This class maintains a list of concrete output generators,
Packit Service 50c9f2
where each method called is delegated to all generators in the list.
Packit Service 50c9f2
Packit Service 50c9f2
To allow small deviations in what is written to the output for each
Packit Service 50c9f2
concrete output generator, it is possible to temporarily disable certain
Packit Service 50c9f2
generators. The OutputList class contains various \c disable() and \c enable()
Packit Service 50c9f2
methods for this. The methods \c OutputList::pushGeneratorState() and 
Packit Service 50c9f2
\c OutputList::popGeneratorState() are used to temporarily save the
Packit Service 50c9f2
set of enabled/disabled output generators on a stack. 
Packit Service 50c9f2
Packit Service 50c9f2
The XML is generated directly from the gathered data structures. In the
Packit Service 50c9f2
future XML will be used as an intermediate language (IL). The output
Packit Service 50c9f2
generators will then use this IL as a starting point to generate the
Packit Service 50c9f2
specific output formats. The advantage of having an IL is that various
Packit Service 50c9f2
independently developed tools written in various languages, 
Packit Service 50c9f2
could extract information from the XML output. Possible tools could be:
Packit Service 50c9f2
- an interactive source browser
Packit Service 50c9f2
- a class diagram generator
Packit Service 50c9f2
- computing code metrics.
Packit Service 50c9f2
Packit Service 50c9f2

Debugging

Packit Service 50c9f2
Packit Service 50c9f2
Since doxygen uses a lot of \c flex code it is important to understand
Packit Service 50c9f2
how \c flex works (for this one should read the \c man page) 
Packit Service 50c9f2
and to understand what it is doing when \c flex is parsing some input. 
Packit Service 50c9f2
Fortunately, when flex is used with the `-d` option it outputs what rules
Packit Service 50c9f2
matched. This makes it quite easy to follow what is going on for a 
Packit Service 50c9f2
particular input fragment. 
Packit Service 50c9f2
Packit Service 50c9f2
To make it easier to toggle debug information for a given flex file I
Packit Service 50c9f2
wrote the following perl script, which automatically adds or removes `-d`
Packit Service 50c9f2
from the correct line in the \c Makefile:
Packit Service 50c9f2
Packit Service 50c9f2
\verbatim
Packit Service 50c9f2
#!/usr/bin/perl 
Packit Service 50c9f2
Packit Service 50c9f2
$file = shift @ARGV;
Packit Service 50c9f2
print "Toggle debugging mode for $file\n";
Packit Service 50c9f2
if (!-e "../src/${file}.l")
Packit Service 50c9f2
{
Packit Service 50c9f2
  print STDERR "Error: file ../src/${file}.l does not exist!\n";
Packit Service 50c9f2
  exit 1;
Packit Service 50c9f2
}
Packit Service 50c9f2
system("touch ../src/${file}.l");
Packit Service 50c9f2
unless (rename "src/CMakeFiles/_doxygen.dir/build.make","src/CMakeFiles/_doxygen.dir/build.make.old") {
Packit Service 50c9f2
  print STDERR "Error: cannot rename src/CMakeFiles/_doxygen.dir/build.make!\n";
Packit Service 50c9f2
  exit 1;
Packit Service 50c9f2
}
Packit Service 50c9f2
if (open(F,"
Packit Service 50c9f2
  unless (open(G,">src/CMakeFiles/_doxygen.dir/build.make")) {
Packit Service 50c9f2
    print STDERR "Error: opening file build.make for writing\n";
Packit Service 50c9f2
    exit 1;
Packit Service 50c9f2
  }
Packit Service 50c9f2
  print "Processing build.make...\n";
Packit Service 50c9f2
  while (<F>) {
Packit Service 50c9f2
    if ( s/flex \$\(LEX_FLAGS\) -d(.*) ${file}.l/flex \$(LEX_FLAGS)$1 ${file}.l/ ) {
Packit Service 50c9f2
      print "Disabling debug info for $file\n";
Packit Service 50c9f2
    }
Packit Service 50c9f2
    elsif ( s/flex \$\(LEX_FLAGS\)(.*) ${file}.l$/flex \$(LEX_FLAGS) -d$1 ${file}.l/ ) {
Packit Service 50c9f2
      print "Enabling debug info for $file.l\n";
Packit Service 50c9f2
    }
Packit Service 50c9f2
    print G "$_";
Packit Service 50c9f2
  }
Packit Service 50c9f2
  close F;
Packit Service 50c9f2
  unlink "src/CMakeFiles/_doxygen.dir/build.make.old";
Packit Service 50c9f2
}
Packit Service 50c9f2
else {
Packit Service 50c9f2
  print STDERR "Warning file src/CMakeFiles/_doxygen.dir/build.make does not exist!\n"; 
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
# touch the file
Packit Service 50c9f2
$now = time;
Packit Service 50c9f2
utime $now, $now, $file;
Packit Service 50c9f2
\endverbatim
Packit Service 50c9f2
Another way to get rules matching / debugging information
Packit Service 50c9f2
from the \c flex code is setting LEX_FLAGS with \c make (`make LEX_FLAGS=-d`).
Packit Service 50c9f2
Packit Service 50c9f2
Note that by running doxygen with `-d lex` you get information about which 
Packit Service 50c9f2
`flex codefile` is used.
Packit Service 50c9f2
Packit Service 50c9f2
\htmlonly
Packit Service 50c9f2
Return to the index.
Packit Service 50c9f2
\endhtmlonly
Packit Service 50c9f2
Packit Service 50c9f2
*/
Packit Service 50c9f2
Packit Service 50c9f2