How can Doxygen handle includes within enum declarations - c

We do have several C-projects targeting resource-constrained systems, which rely heavily on enums defined through preprocessor macros in special resource files. These files get included within the enum definition.
This concept is used to have the user of our API to "be only allowed" to edit the resource definition file, but not needing to touch the header file where these enums are actually defined. Additionally it allows to generate strings for these events, too.
Example for a resource file
DEF_SOME_EVENT_TYPE(EVENT_ALERT)
DEF_OTHER_EVENT_TYPE(EVENT_OTHER_ALERT)
DEF_SOME_EVENT_TYPE(EVENT_FLASH)
DEF_SOME_EVENT_TYPE(EVENT_BEEP)
Example for the associated enum definition
enum some_event_e
{
#define DEF_SOME_EVENT_TYPE(name) name,
#define DEF_SOME_OTHER_EVENT_TYPE(name)
#include "resource_definitions.g"
#undef DEF_SOME_EVENT_TYPE
#undef DEF_SOME_OTHER_EVENT_TYPE
SOME_EVENT_COUNT
};
enum some_other_event_e
{
#define DEF_SOME_EVENT_TYPE(name) name,
#define DEF_SOME_OTHER_EVENT_TYPE(name)
#include "resource_definitions.g"
#undef DEF_SOME_EVENT_TYPE
#undef DEF_SOME_OTHER_EVENT_TYPE
SOME_OTHER_EVENT_COUNT
};
When trying to document the enumerators, doxygen seems to not properly expand these macros and include the resource definition file.
Suppose we have the following documentation block:
/*!
#enum some_event_e
#brief Some event identifiers
*/
/*!
#var some_event_e::EVENT_ALERT
#brief alert event
*/
/*!
#var some_event_e::SOME_EVENT_COUNT
#brief Total number of some events
*/
Doxygen will properly document SOME_EVENT_COUNT, but will throw a warnign for EVENT_ALERT.
warning: documented symbol 'some_event_e::EVENT_ALERT' was not declared or defined.
ENABLE_PREPROCESSING and MACRO_EXPANSION are both set to YES in Doxyfile and I've added *.g (the file-extension used for resource definitions) to the INCLUDE_FILE_PATTERNS and did add it to EXTENSION_MAPPING via g=C. I'm using doxygen version 1.8.16.
Is there a way to be able to document enum values declared in this manner? In some cases it is really useful to use this sort of macro-magic to define enums, so it would be immensely helpful if it was possible to document these with doxygen.

Related

doxygen to document function declarations within C header files

Doxygen is able to document structs but it's not exporting any function declarations or macro definitions.
For instance these defined in headers are not exported.
/** Total instances */
#define TOTAL 10
/** Initializer */
void InitProduct(Product *product, const char *productName);
I'm using Doxygen GUI on Windows, appreciate a GUI reference.
Doxygen is fussy about what documentation it extracts when not EXTRACT_ALL.
Structures and classes are generally okay; functions and variables not so.
To get documentation extracted for functions and variables at the file-level scope, there needs to be a #file documentation element in that file:
/** #file frobulator.c
* Optionally describe the file...
*/
/** #brief My Frobulator.
*/
void frobulator () { ... }
This is for both headers and source files.
For functions and variables at namespace scope, the namespace also needs to be documented with #namespace or in situ. Unlike other elements, namespaces have no "single" point of declaration where documentation can be placed. I usually end up creating a separate .dox file to contain #namespace docs in C comment blocks.

Documenting conditional exclusive code in Doxygen

Consider
// EXTERNAL_MACRO is an external macro defined to some value by build system
#if EXTERNAL_MACRO == 1
# define EXCLUSIVE_MACRO_ONE
#elif EXTERNAL_MACRO == 2
# define EXCLUSIVE_MACRO_TWO
#else
# define EXCLUSIVE_MACRO_OTHER
#endif
At built time, only one of the EXCLUSIVE_MACRO_... macros is defined.
How can one document all three EXCLUSIVE_MACRO_... macros in Doxygen?
PREDEFINED configuration setting is not helpful for this because it allows to define EXTERNAL_MACRO to only a single value (and therefore document only a single EXCLUSIVE_MACRO_...).
This SO answer offers a work-around solution that does the job but it requires an additional logic. I am looking for a simpler answer, one that uses Doxygen configuration (if possible) rather than modifying the original code (though some modification is of course fine).
See related question and answer:
Document a config macro with doxygen
Basically:
In the doxygen configuration file, add:
PREDEFINED = IN_DOXYGEN
Somewhere in the source code, add:
/*
Exporting build configuration macros to doxygen,
so they get documented.
*/
#ifdef IN_DOXYGEN
# define EXCLUSIVE_MACRO_ONE
# define EXCLUSIVE_MACRO_TWO
# define EXCLUSIVE_MACRO_THREE
#endif /* IN_DOXYGEN */
Then the documentation for these macros is picked up properly.
If you don't want to change the source, you can add EXCLUSIVE_MACRO_ONE and friends in PREDEFINED, instead of setting EXTERNAL_MACRO.
Inspired by answer.
PROBLEM: We have an existing header that, based on an external macro (provided by build system), defines one of several exclusive macros during compilation. Since only one of the compile-time macros is defined (for each individual build), it is difficult to add Doxygen documentation to all of the exclusive options.
// DEFINED_EXTERNALLY is a macro provided by the build system (e.g. via -D). It is defined as 1, 2, or some other natural number.
// Based on DEFINED_EXTERNALLY we want to define one of several exclusive DEFINED_HERE_... macros (e.g. DEFINED_HERE_1, DEFINED_HERE_2, and DEFINED_HERE_OTHER).
// First, we check that none of the DEFINED_HERE_... macros is defined yet.
#if defined(DEFINED_HERE_1) || defined(DEFINED_HERE_2) || defined(DEFINED_HERE_OTHER)
# error "Conflict: macro DEFINED_HERE_... is already defined!"
#endif
// Then, we define one, and only one, of the DEFINED_HERE_... macros.
#if DEFINED_EXTERNALLY == 1
# define DEFINED_HERE_1
#elif DEFINED_EXTERNALLY == 2
# define DEFINED_HERE_2
#else
# define DEFINED_HERE_OTHER
#endif
SOLUTION: We temporarily define all variants of the DEFINED_HERE_... macros, together with their documentation. This will cause Doxygen to generate documentation for all of them. We then undefine all of the variants and resume normal macro definition logic.
As a result, we will have documentation for all variants yet only one of them will be defined during compilation as was the case before adding the documentation.
Original code
// DEFINED_EXTERNALLY is a macro provided by the build system (e.g. via -D). It is defined as 1, 2, or some other natural number.
// Based on DEFINED_EXTERNALLY we want to define one of several DEFINED_HERE_... macros (e.g. DEFINED_HERE_1, DEFINED_HERE_2, and DEFINED_HERE_OTHER).
// First, we check that none of the DEFINED_HERE_... macros is defined yet.
#if defined(DEFINED_HERE_1) || defined(DEFINED_HERE_2) || defined(DEFINED_HERE_OTHER)
# error "Conflict: macro DEFINED_HERE_... is already defined!"
#endif
New inserted code to generate documentation
/// \brief Value 1.
/// \details It does the following...
#define DEFINED_HERE_1
#undef DEFINED_HERE_1
/// \brief Value 2.
/// \details It does the following...
#define DEFINED_HERE_2
#undef DEFINED_HERE_2
/// \brief Other value.
/// \details It does the following...
#define DEFINED_HERE_OTHER
#undef DEFINED_HERE_OTHER
Original code
// Then, we define one, and only one, of the DEFINED_HERE_... macros.
#if DEFINED_EXTERNALLY == 1
# define DEFINED_HERE_1
#elif DEFINED_EXTERNALLY == 2
# define DEFINED_HERE_2
#else
# define DEFINED_HERE_OTHER
#endif
NB no change to the default Doxygen settings is required
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
PREDEFINED =
EXPAND_AS_DEFINED =

Why is Doxygen grouping enums with the same name from different C files?

I'm using Doxygen 1.8.5 and having the same exact problem as in the following question, only the language is C and the enums are in the C files:
Doxygen C# XML comments: multiply enum's with same name and different scope got merged?
According to https://bugzilla.gnome.org/show_bug.cgi?id=522193 it was fixed in 1.6.0, but I'm guessing Doxygen isn't treating different C files as having different namespaces.
The enums in question pertain only to each specific file, but are called the same name because they are used for the same purpose in that file (for flags used to track status information about that module, for example). The C compiler has no problem with this, but Doxygen combines them.
Example:
file1.c
enum status_flags {
sfACTIVE,
sfSHUTDOWN,
sfWARNING,
};
file2.c
enum status_flags {
sfSTANDBY,
sfSCREEN_OWNED,
};
The doxygen file will generate a single blob of both enums combined, including the comments for each member, and reference them in the documentation for both files.
enum status_flags
Enumerator
sfACTIVE
sfSHUTDOWN
sfWARNING
sfSTANDBY
sfSCREEN_OWNED
Definition at line 42 of file file1.c.
and
enum status_flags
Enumerator
sfACTIVE
sfSHUTDOWN
sfWARNING
sfSTANDBY
sfSCREEN_OWNED
Definition at line 65 of file file2.c.
I've tried making each file a member of its own #addtogroup, and I've made sure each file has an #file at the top, but it's still mixing all of these enums together which are supposed to be private to that particular C file. It would be a bit of a pain if I were forced to rename each of these enums, as there are dozens of applications in the code which all follow a similar format and use private enums of the same name with different flags. The compiler is perfectly happy to work with them.
Any ideas?
Anonymous typedef enum also have this same issue,
typedef enum {
sfACTIVE,
sfSHUTDOWN,
sfWARNING
} status_flags;
results in the combining issue, but Doxygen appears
to give priority to the enumeration, so combining
does not happen when you do this:
typedef enum status_flags_f1 {
sfACTIVE,
sfSHUTDOWN,
sfWARNING
} status_flags;
typedef enum status_flags_f2 {
sfSTANDBY,
sfSCREEN_OWNED
} status_flags;
This only works if TYPEDEF_HIDES_STRUCT is set to NO in the Doxyfile configuration file, which is the default.

C multiple keywords for return type in function definition

I am looking over some C code but can't for the life of me figure out what to google to figure out what the following extra identifier is in the following function definition:
// Whats this? It seems there are two return types?
// |
// V
XN_C_API XnStatus xnInit(XnContext** ppContext) {
...
}
I apologize if this is too far removed from its original context (its from OpenNI and I would be more than happy to post up a link if need be)
It's a symbol defined using #define. Search through the code to find where it's defined. The actual return type of your function is XnStatus, while XN_C_API is likely defined to be a set of modifier. These are typically used to define exported symbols or other attributes for functions that have the particular attribute.
For example, in my code (a DLL project on Windows), I have this:
#ifdef MGR_EXPORTS
#define MGR_API __declspec(dllexport)
#else
#define MGR_API __declspec(dllimport)
#endif
...
#define MGRAPI StatusCode __declspec(nothrow) WINAPI
All the public (exported) function declarations look like this:
MGR_API MGRAPI MgrInit ()
The first symbol MGR_API is used to control how symbols are exported from the DLL; the other, MGRAPI helps declare all public functions with the same set of modifiers and the same return type (which is StatusCode).
If there's ever a need to update the declaration of all public functions in this project it's easy because only the defined symbols need to be changed and all functions take the change right away.
Is defined like this
#define XN_C_API XN_C_API_IMPORT
#define XN_C_API_IMPORT XN_API_IMPORT
#define XN_API_IMPORT __declspec(dllimport)
__declspec(dllimport) means that the function is imported from a DLL file.

How can I keep doxygen from documenting #defines in a C file?

I have #define values in headers that I certainly want Doxygen to document but I have others in C files that I treat as static constants and I don't want Doxygen to document them. Something as simple and stupid as
#define NUMBER_OF(a) (sizeof((a))/sizeof((a)[0]))
#define MSTR(e) #e
How can I keep Doxygen from putting those #defines in the documentation it creates? I've tried marking it with #internal but that didn't seem to help.
A somewhat-related question on Doxygen and #define, how can I get:
#define SOME_CONSTANT 1234 /**< An explanation */
to put "SOME_CONSTANT" and "An explanation" but not "1234" in the output?
There is no need to use the \cond and \endcond commands. You can hide the initializer by simply using the \hideinitializer command:
#define SOME_CONSTANT 1234 /**< An explanation #hideinitializer */
Regarding the first question, you may set HIDE_UNDOC_MEMBERS = YES and only the macros having a Doxygen documentation block will be shown in the output.
You can set MAX_INITIALIZER_LINES = 0 in your doxyfile to hide the values of your defines.
You can exclude any part of code from Doxygen parsing with \cond ... \endcond tags.
edit: Some related questions:
How can Doxygen exclude a C++ class?
Exclude some classes from doxygen documentation
You only want to document what is declared in the .h files. I'm assuming you declare all static functions and variables as static in your .c files. All the remaining are declared in .h corresponding files also. These are your "public" members.
What I like to do in this case, and I believe doxygen was more designed to be used this way is:
in your Doxyfile, set EXTRACT_ALL = NO and add the directory where your .h files are to INPUT
add /** \file */ to all your .h files (but not your .c files).
This will index only what is contained in your .h files. You can still add the directory containing your .c files to INPUT at your Doxyfile, and they will be scanned for additional documentation for your "public" members...
It will no doubt still seem noisy and unnatural, but to address your other question, try:
/** An explanation */
#define SOME_CONSTANT /** #cond */ 1234 /** #endcond */
I solved this problem by moving my documentation from the .c file to the .h file. Then run doxygen only on the .h file.
Then the items that I want to document (the 'public' items) are intrinsically what doxygen picks up.
Because I have been previously careful to put 'public' items in the .h file and 'private' items in the .c file this works very well.
This technique came to mind when I noticed that doxygen was pulling in the includes. It struck me that if I were to also move the subset of includes that the calling module would need to use my module, then that list would be documented as well.
This technique has an additional benefit: I can put the documentation in one terminal window and the source in a different terminal window while updating the documentation.
Sometimes you may have a define which you want to document, but want doxygen to treat it differently (or even ignore it completely to avoid parsing errors).
For this you can define the #define in doxygen differently than in your sourcecode.
Example:
Some compilers allow variable linkage to specific segments, i.e.:
const int myvar # "segment_of_myvar_in_memory"=123;
=> doxygen would parse the "segment_of_myvar_in_memory" part as variable name which is not desired.
We could use a define for it:
#define __link_to_segment(name) # name
const int myvar __link_to_segment("segment_of_myvar_in_memory")=123;
If Preprocessing is active, Doxygen interprets our variable now as a function because of the function-like define using brackets..
But if we redefine our define within the Doxyfile, behaviour changes:
PREDEFINED = __link_to_segment(a)=
now the variable is parsed correctly as variable - also all types or keywords in front are correctly shown as keywords.
A nice side effekt:
In case you use 2 different IDEs with your code (one IDE for compiling&debugging, one for editing), you will also discover that some IDEs (i.e. Eclipse) have problems parsing variables with #"segment name". Using the approach above, you can redefine the __link_to_segment(name) there too:
#define __link_to_segment(name)
i.e. Eclipse will then show and parse the variable correctly, whereas the "compiling&debugging" IDE can still link the variable to its segment name.

Resources