|
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 |
*/
|