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