I am trying to document a header file which has different "overloads" when parsed by C or C++.
#ifdef __cplusplus
/// myfuncA
void myfuncA();
/// MYMACRO_A
#define MYMACRO_A() \
myfuncA();
#else
/// myfuncB
void myfuncB();
/// MYMACRO_B
#define MYMACRO_B() \
myfuncB();
#endif
I want all four of these functions and macros to be collected and individually documented by Doxygen. This is a sensible use-case in my application; these are C and C++ specific overloads to a core function, and the doc will specify which can be called by which language.
Alas, it is proving impossible to make Doxygen simultaneously document all four of them!
When my Doxyfile includes
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
SKIP_FUNCTION_MACROS = NO
then Doxygen will evaluate ifdef __cplusplus to 0 and document only myfuncB and MYMACRO_B.
Alternatively, when I set
ENABLE_PREPROCESSING = NO
then Doxygen will not document any macros at all, and so document only myfuncA and myfuncB.
Attempted solutions
- I have tried every combination of
MACRO_EXPANSIONandEXPAND_ONLY_PREDEF, and exposing the macros toEXPAND_AS_DEFINEDandPREDEFINEDwith no success. - I tried setting
so that Doxygen would remove theENABLE_PREPROCESSING = YES PREDEFINED = ifdef __cplusplus=#ifbranches before beginning parsing and evaluation, but this horrible hack is too complicated for my application. - I have tried foregoing Doxygen parsing the macros, and instead trying to document them completely fictitiously as "orphaned" functions - but it doesn't seem to work! Use of
@defand@fnrequire Doxygen eventually encounter the real signature. - One could imagine a variant of
PREDEFINEDlikePREDEFINED_IN_TURNwhich re-parses the source code for each set of preprocessor values. Then one could use
but alas, there is no such key (and seems non-trivial to hack). Of course this would not work with my example code immediately which usesENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES SKIP_FUNCTION_MACROS = NO # crucially... PREDEFINED_IN_TURN = __cplusplus=0 __cplusplus=1#ifdefover#if. - a functioning but invasive solution is to refactor the code such
that every
#if/#elsebranch is explored when a macro likeDOXYGENis defined. This requires removing all#elseclauses:
along with Doxyfile#if defined(__cplusplus) || defined(DOXYGEN) ... #endif #if !defined(__cplusplus) || defined(DOXYGEN) ... #endif
Alas this is a major and unacceptable change to the source-code in my application, and introduces bug vulnerability.ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES SKIP_FUNCTION_MACROS = NO # crucially PREDEFINED = DOXYGEN
Unsatisfying solution
The only workaround I can think up to display all four functions/macros (without major refactor) is to spoof the macros with function signatures that we hide from the compilers (but not doxygen) using #if 0:
#ifdef __cplusplus
/// myfuncA
void myfuncA();
#define MYMACRO_A() \
myfuncA();
#if 0
/// MYMACRO_A
void MYMACRO_A();
#endif
#else
/// myfuncB
void myfuncB();
#define MYMACRO_B() \
myfuncB();
#if 0
/// MYMACRO_B
void MYMACRO_B();
#endif
#endif
The documentation will now include myfuncA, myfuncB, MYMACRO_A and MYMACRO_B but alas the latter two will be listed as functions rather than as macros.
Is this an unsupported use-case? Otherwise, what is a sensible, reliable method to achieve the documenting of all four entities, where the latter two are correctly reported as macros?
(I am using Doxygen 1.13.2 on MacOS)