Blame doc/preprocessing.doc

Packit 1c1d7e
/******************************************************************************
Packit 1c1d7e
 *
Packit 1c1d7e
 * 
Packit 1c1d7e
 *
Packit 1c1d7e
 * Copyright (C) 1997-2015 by Dimitri van Heesch.
Packit 1c1d7e
 *
Packit 1c1d7e
 * Permission to use, copy, modify, and distribute this software and its
Packit 1c1d7e
 * documentation under the terms of the GNU General Public License is hereby 
Packit 1c1d7e
 * granted. No representations are made about the suitability of this software 
Packit 1c1d7e
 * for any purpose. It is provided "as is" without express or implied warranty.
Packit 1c1d7e
 * See the GNU General Public License for more details.
Packit 1c1d7e
 *
Packit 1c1d7e
 * Documents produced by Doxygen are derivative works derived from the
Packit 1c1d7e
 * input used in their production; they are not affected by this license.
Packit 1c1d7e
 *
Packit 1c1d7e
 */
Packit 1c1d7e
/*! \page preprocessing Preprocessing
Packit 1c1d7e
Packit 1c1d7e
Source files that are used as input to doxygen can be parsed by doxygen's
Packit 1c1d7e
built-in C-preprocessor.
Packit 1c1d7e
Packit 1c1d7e
By default doxygen does only partial preprocessing. That is, it 
Packit 1c1d7e
evaluates conditional compilation statements (like \c \#if) and 
Packit 1c1d7e
evaluates macro definitions, but it does not perform macro expansion.
Packit 1c1d7e
Packit 1c1d7e
So if you have the following code fragment
Packit 1c1d7e
\verbatim
Packit 1c1d7e
#define VERSION 200
Packit 1c1d7e
#define CONST_STRING const char *
Packit 1c1d7e
Packit 1c1d7e
#if VERSION >= 200
Packit 1c1d7e
  static CONST_STRING version = "2.xx";
Packit 1c1d7e
#else
Packit 1c1d7e
  static CONST_STRING version = "1.xx";
Packit 1c1d7e
#endif
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
Then by default doxygen will feed the following to its parser:
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
#define VERSION
Packit 1c1d7e
#define CONST_STRING
Packit 1c1d7e
Packit 1c1d7e
  static CONST_STRING version = "2.xx";
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
You can disable all preprocessing by setting 
Packit 1c1d7e
\ref cfg_enable_preprocessing "ENABLE_PREPROCESSING" to \c 
Packit 1c1d7e
NO in the configuration file. In the case above doxygen will then read
Packit 1c1d7e
both statements, i.e.:
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
  static CONST_STRING version = "2.xx";
Packit 1c1d7e
  static CONST_STRING version = "1.xx";
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
In case you want to expand the \c CONST_STRING macro, you should set the
Packit 1c1d7e
\ref cfg_macro_expansion "MACRO_EXPANSION" tag in the config file 
Packit 1c1d7e
to \c YES. Then the result after preprocessing becomes:
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
#define VERSION
Packit 1c1d7e
#define CONST_STRING
Packit 1c1d7e
Packit 1c1d7e
  static const char * version = "2.xx";
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
Note that doxygen will now expand \e all macro definitions 
Packit 1c1d7e
(recursively if needed). This is often too much. Therefore, doxygen also 
Packit 1c1d7e
allows you to expand only those defines that you explicitly 
Packit 1c1d7e
specify. For this you have to set the 
Packit 1c1d7e
\ref cfg_expand_only_predef "EXPAND_ONLY_PREDEF" tag to \c YES
Packit 1c1d7e
and specify the macro definitions after 
Packit 1c1d7e
the \ref cfg_predefined "PREDEFINED" or 
Packit 1c1d7e
\ref cfg_expand_as_defined "EXPAND_AS_DEFINED" tag.  
Packit 1c1d7e
Packit 1c1d7e
A typically example where some help from the preprocessor is needed is
Packit 1c1d7e
when dealing with the language extension from Microsoft: \c __declspec. The same goes
Packit 1c1d7e
for GNU's \c \__attribute__ extension. Here is an example function.
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
extern "C" void __declspec(dllexport) ErrorMsg( String aMessage,...);
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
When nothing is done, doxygen will be confused and see \c __declspec as
Packit 1c1d7e
some sort of function. To help doxygen one typically uses the following
Packit 1c1d7e
preprocessor settings:
Packit 1c1d7e
Packit 1c1d7e
\verbatim  
Packit 1c1d7e
ENABLE_PREPROCESSING   = YES
Packit 1c1d7e
MACRO_EXPANSION        = YES
Packit 1c1d7e
EXPAND_ONLY_PREDEF     = YES
Packit 1c1d7e
PREDEFINED             = __declspec(x)=
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
This will make sure the \c __declspec(dllexport) is removed before doxygen
Packit 1c1d7e
parses the source code.
Packit 1c1d7e
Packit 1c1d7e
Similar settings can be used for removing \c \__attribute__ expressions from the input:
Packit 1c1d7e
Packit 1c1d7e
\verbatim  
Packit 1c1d7e
ENABLE_PREPROCESSING   = YES
Packit 1c1d7e
MACRO_EXPANSION        = YES
Packit 1c1d7e
EXPAND_ONLY_PREDEF     = YES
Packit 1c1d7e
PREDEFINED             = __attribute__(x)=
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
For a more complex example, suppose you have the following obfuscated 
Packit 1c1d7e
code fragment of an abstract base class called \c IUnknown:
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
/*! A reference to an IID */
Packit 1c1d7e
#ifdef __cplusplus
Packit 1c1d7e
#define REFIID const IID &
Packit 1c1d7e
#else
Packit 1c1d7e
#define REFIID const IID *
Packit 1c1d7e
#endif
Packit 1c1d7e
Packit 1c1d7e
Packit 1c1d7e
/*! The IUnknown interface */
Packit 1c1d7e
DECLARE_INTERFACE(IUnknown)
Packit 1c1d7e
{
Packit 1c1d7e
  STDMETHOD(HRESULT,QueryInterface) (THIS_ REFIID iid, void **ppv) PURE;
Packit 1c1d7e
  STDMETHOD(ULONG,AddRef) (THIS) PURE;
Packit 1c1d7e
  STDMETHOD(ULONG,Release) (THIS) PURE;
Packit 1c1d7e
};
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
without macro expansion doxygen will get confused, but we may not want to 
Packit 1c1d7e
expand the \c REFIID macro, because it is documented and the user that reads 
Packit 1c1d7e
the documentation should use it when implementing the interface.
Packit 1c1d7e
Packit 1c1d7e
By setting the following in the config file:
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
ENABLE_PREPROCESSING = YES
Packit 1c1d7e
MACRO_EXPANSION      = YES
Packit 1c1d7e
EXPAND_ONLY_PREDEF   = YES
Packit 1c1d7e
PREDEFINED           = "DECLARE_INTERFACE(name)=class name" \
Packit 1c1d7e
                       "STDMETHOD(result,name)=virtual result name" \
Packit 1c1d7e
                       "PURE= = 0" \
Packit 1c1d7e
                       THIS_= \
Packit 1c1d7e
                       THIS= \
Packit 1c1d7e
		       __cplusplus
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
we can make sure that the proper result is fed to doxygen's parser:
Packit 1c1d7e
\verbatim
Packit 1c1d7e
/*! A reference to an IID */
Packit 1c1d7e
#define REFIID
Packit 1c1d7e
Packit 1c1d7e
/*! The IUnknown interface */
Packit 1c1d7e
class  IUnknown
Packit 1c1d7e
{
Packit 1c1d7e
  virtual  HRESULT   QueryInterface ( REFIID iid, void **ppv) = 0;
Packit 1c1d7e
  virtual  ULONG   AddRef () = 0;
Packit 1c1d7e
  virtual  ULONG   Release () = 0;
Packit 1c1d7e
};
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
Note that the \ref cfg_predefined "PREDEFINED" tag accepts function 
Packit 1c1d7e
like macro definitions
Packit 1c1d7e
(like \c DECLARE_INTERFACE ), normal macro 
Packit 1c1d7e
substitutions (like \c PURE and \c THIS) and plain 
Packit 1c1d7e
defines (like \c __cplusplus).
Packit 1c1d7e
Packit 1c1d7e
Note also that preprocessor definitions that are normally defined 
Packit 1c1d7e
automatically by the preprocessor (like \c __cplusplus), have to be defined 
Packit 1c1d7e
by hand with doxygen's parser (this is done because these defines
Packit 1c1d7e
are often platform/compiler specific).
Packit 1c1d7e
Packit 1c1d7e
In some cases you may want to substitute a macro name or function by 
Packit 1c1d7e
something else without exposing the result to further macro substitution.
Packit 1c1d7e
You can do this but using the := operator instead of 
Packit 1c1d7e
=
Packit 1c1d7e
Packit 1c1d7e
As an example suppose we have the following piece of code:
Packit 1c1d7e
\verbatim
Packit 1c1d7e
#define QList QListT
Packit 1c1d7e
class QListT
Packit 1c1d7e
{
Packit 1c1d7e
};
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
Then the only way to get doxygen interpret this as a class definition
Packit 1c1d7e
for class \c QList is to define:
Packit 1c1d7e
\verbatim
Packit 1c1d7e
PREDEFINED = QListT:=QList
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
Here is an example provided by Valter Minute and Reyes Ponce that helps 
Packit 1c1d7e
doxygen to wade through the boilerplate code in Microsoft's ATL \& MFC 
Packit 1c1d7e
libraries:
Packit 1c1d7e
Packit 1c1d7e
\verbatim
Packit 1c1d7e
PREDEFINED           = "DECLARE_INTERFACE(name)=class name" \
Packit 1c1d7e
                       "STDMETHOD(result,name)=virtual result name" \
Packit 1c1d7e
                       "PURE= = 0" \
Packit 1c1d7e
                       THIS_= \
Packit 1c1d7e
                       THIS= \
Packit 1c1d7e
                       DECLARE_REGISTRY_RESOURCEID=// \
Packit 1c1d7e
                       DECLARE_PROTECT_FINAL_CONSTRUCT=// \
Packit 1c1d7e
                       "DECLARE_AGGREGATABLE(Class)= " \
Packit 1c1d7e
                       "DECLARE_REGISTRY_RESOURCEID(Id)= " \
Packit 1c1d7e
                       DECLARE_MESSAGE_MAP= \
Packit 1c1d7e
                       BEGIN_MESSAGE_MAP=/* \
Packit 1c1d7e
                       END_MESSAGE_MAP=*/// \
Packit 1c1d7e
                       BEGIN_COM_MAP=/* \
Packit 1c1d7e
                       END_COM_MAP=*/// \
Packit 1c1d7e
                       BEGIN_PROP_MAP=/* \
Packit 1c1d7e
                       END_PROP_MAP=*/// \
Packit 1c1d7e
                       BEGIN_MSG_MAP=/* \
Packit 1c1d7e
                       END_MSG_MAP=*/// \
Packit 1c1d7e
                       BEGIN_PROPERTY_MAP=/* \
Packit 1c1d7e
                       END_PROPERTY_MAP=*/// \
Packit 1c1d7e
                       BEGIN_OBJECT_MAP=/* \
Packit 1c1d7e
                       END_OBJECT_MAP()=*/// \
Packit 1c1d7e
                       DECLARE_VIEW_STATUS=// \
Packit 1c1d7e
                       "STDMETHOD(a)=HRESULT a" \
Packit 1c1d7e
                       "ATL_NO_VTABLE= " \
Packit 1c1d7e
                       "__declspec(a)= " \
Packit 1c1d7e
                       BEGIN_CONNECTION_POINT_MAP=/* \
Packit 1c1d7e
                       END_CONNECTION_POINT_MAP=*/// \
Packit 1c1d7e
                       "DECLARE_DYNAMIC(class)= " \
Packit 1c1d7e
                       "IMPLEMENT_DYNAMIC(class1, class2)= " \
Packit 1c1d7e
                       "DECLARE_DYNCREATE(class)= " \
Packit 1c1d7e
                       "IMPLEMENT_DYNCREATE(class1, class2)= " \
Packit 1c1d7e
                       "IMPLEMENT_SERIAL(class1, class2, class3)= " \
Packit 1c1d7e
                       "DECLARE_MESSAGE_MAP()= " \
Packit 1c1d7e
                       TRY=try \
Packit 1c1d7e
                       "CATCH_ALL(e)= catch(...)" \
Packit 1c1d7e
                       END_CATCH_ALL= \
Packit 1c1d7e
                       "THROW_LAST()= throw"\
Packit 1c1d7e
                       "RUNTIME_CLASS(class)=class" \
Packit 1c1d7e
                       "MAKEINTRESOURCE(nId)=nId" \
Packit 1c1d7e
                       "IMPLEMENT_REGISTER(v, w, x, y, z)= " \
Packit 1c1d7e
                       "ASSERT(x)=assert(x)" \
Packit 1c1d7e
                       "ASSERT_VALID(x)=assert(x)" \
Packit 1c1d7e
                       "TRACE0(x)=printf(x)" \
Packit 1c1d7e
                       "OS_ERR(A,B)={ #A, B }" \
Packit 1c1d7e
                       __cplusplus \
Packit 1c1d7e
                       "DECLARE_OLECREATE(class)= " \
Packit 1c1d7e
                       "BEGIN_DISPATCH_MAP(class1, class2)= " \
Packit 1c1d7e
                       "BEGIN_INTERFACE_MAP(class1, class2)= " \
Packit 1c1d7e
                       "INTERFACE_PART(class, id, name)= " \
Packit 1c1d7e
                       "END_INTERFACE_MAP()=" \
Packit 1c1d7e
                       "DISP_FUNCTION(class, name, function, result, id)=" \
Packit 1c1d7e
                       "END_DISPATCH_MAP()=" \
Packit 1c1d7e
                       "IMPLEMENT_OLECREATE2(class, name, id1, id2, id3, id4,\
Packit 1c1d7e
                        id5, id6, id7, id8, id9, id10, id11)="
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
Packit 1c1d7e
As you can see doxygen's preprocessor is quite powerful, but if you want
Packit 1c1d7e
even more flexibility you can always write an input filter and specify it 
Packit 1c1d7e
after the \ref cfg_input_filter "INPUT_FILTER" tag.
Packit 1c1d7e
Packit 1c1d7e
If you are unsure what the effect of doxygen's preprocessing will be
Packit 1c1d7e
you can run doxygen as follows:
Packit 1c1d7e
\verbatim
Packit 1c1d7e
  doxygen -d Preprocessor
Packit 1c1d7e
\endverbatim
Packit 1c1d7e
This will instruct doxygen to dump the input sources to standard output after
Packit 1c1d7e
preprocessing has been done (Hint: set QUIET = YES and 
Packit 1c1d7e
WARNINGS = NO in the configuration file to disable any other 
Packit 1c1d7e
output).
Packit 1c1d7e
Packit 1c1d7e
\htmlonly
Packit 1c1d7e
Go to the next section or return to the
Packit 1c1d7e
 index.
Packit 1c1d7e
\endhtmlonly
Packit 1c1d7e
Packit 1c1d7e
*/