Documenting conditional exclusive code in Doxygen - c-preprocessor

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 =

Related

How can Doxygen handle includes within enum declarations

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.

Prevent inclusion of headers into same file in C

I'm looking for a way to enforce that certain headers cannot be included into the same file.
To explain the situation further, assume I have the headers
a_1.h, b_1.h
and
a_2.h, b_2.h
I want to prevent the inclusion of _1 and _2 files into the same file, regardless of if they were
a_ or b_
Assuming that mixing the _1 and _2 headers is a mistake that needs to be caught, a simple way of catching it is to define and check guard macros to check for mixed usage of these headers and use the #error directive to report errors.
For example, the a_1.h header can include this code:
#ifndef A_1_H__INCLUDED
#define A_1_H__INCLUDED
/* Define header set as 1 if not already defined. */
#ifndef HEADER_SET
#define HEADER_SET 1
#endif
/* Check for consistent header set usage. */
#if HEADER_SET != 1
#error "Inconsistent header sets"
#endif
/* Other header stuff ... */
#endif /* A_1_H__INCLUDED */
The other headers will be similar but the _2 headers will have #define HEADER_SET 2 and #if HEADER_SET != 2.
Remember that ANY other file in the build process can include a header. With the typical include guard: #ifndef MYHEADER \n #include MYHEADER, the header code is only inserted on the first instance. After that, the compiler has eaten it and remembers and doesn't need to include it again. Think of compiling as putting ALL the source code into one file and turning that into a binary. (you know, "compiling" as in putting it all in a pile). So it's not "into the same file" it's "into the same build".
You want a header file to be mutually exclusive with another header file. (Like, say, if you've got code that targets specific hardware via includes, and you obviously can't build towards two chips at the same time.) First off, if that's an issue, you should really have a single place where such things are defined (like the build script) so that's not a problem. But if you want a simple safeguard:
#ifndef PPC_e6500
#define PPC_e6500
#ifdef LINUX
#error This processor ain't big enough for the both of us, Tux. This here's 8548 territory!
#endif
That will fail to build and you can figure out who did whatever horrible thing that tried to build towards two targets at once.

Why might need include a source file that?

I am to port h264 codec in an embedded device. The ffmpeg source code uses the following construction:
#undef CHROMA_IDC
#define CHROMA_IDC 3
#include "h264_mc_template.c"
static av_noinline void FUNC(hl_decode_mb_444)(const H264Context *h, H264SliceContext *sl)
{
...
}
Why do I need to include such a source file? Isn't that used only for the header?
the "template" suffix hints at the fact that the code depends on some preprocessor directives.
I checked the source and at the beginning there's
#if CHROMA_IDC == 1
# define MCFUNC(n) FUNC(n ## _420)
#elif CHROMA_IDC == 2
# define MCFUNC(n) FUNC(n ## _422)
#elif CHROMA_IDC == 3
# define MCFUNC(n) FUNC(n ## _444)
#endif
note that you have #define CHROMA_IDC 3 before including this file.
This tells the preprocessor to use define MCFUNC(n) FUNC(n ## _444) in the included file.
the source could have been left alone in the makefile but with a -DCHROMA_IDC=3 directive, and in that case, the template cannot be reused for other source files because of multiple redefinition (the functions in this source file are static to avoid multiple redefinition if the template is instanciated more than once)
Why using a template? probably for performance issues, to avoid a call chain and some tests to branch on the required behaviour. ffmpeg cannot afford to be slow on the encoding functions.

Redefining macros with old contents / Making a file include counter

I want to count the amount of includes of one specific file.
My first idea was to define a macro holding the count and redefining it when a specific file is included. I have to find a way that the macro is expanded, to be used in a new definition with the same name again, else its old value would simply be destroyed by undef. Is there a way to expand the macros when the macro is defined. Or is there an other way to count including files?
FILE main.c:
#define INCLUDE_COUNT 0
// some other files include the file include_counter.h here
You would think that the compiler could replace INCLUDE_COUNT by 0 or one of its redefinitions in the first line, but it doesn't because macros inside macro-definitions are expanded when the macro is used in non-macro code.
FILE include_counter.h:
#define OLD_INCLUDE_COUNT (INCLUDE_COUNT)
#undef INCLUDE_COUNT
#define INCLUDE_COUNT (OLD_INCLUDE_COUNT + 1)
// INCLUDE_COUNT would be expanded to ((INCLUDE_COUNT) + 1)
Is there a way to expand the macros when the macro is defined.
Yes. But beware... using this as a means of generating unique symbols may cause unexpected linker issues if your symbols have external linkage.
Overview
The key problem here is that macros are not variables. With variables, if I have x=3*3; y=x;, then I'm assigning the value of x to y. With macros, if I have #define PPX 3*3 #define PPY PPX, then I'm literally assigning PPX to PPY. If I then evaluate PPY, it expands to PPX, and then to 3*3 but only because PPX is currently defined as 3*3.
However, there is a way around this. The preprocessor can evaluate expressions; it just uses conditional directives to do so. But due to the fact that this can branch, we can define macros conditionally based on PPX's value (as opposed to its replacement list). For example:
#if (PPX)%10==9
# define PPX_DIGIT_0 9
#elif (PPX)%10==8
# define PPX_DIGIT_0 8
...
So whereas PPY critically relies on PPX being defined as 3*3 to expand to 3*3; since PPX_DIGIT_0 is literally defined as 9, PPX can be undefined, and PPX_DIGIT_0 will still expand to 9. Note also that the conditional played a role in reducing the expression; (3*3)%10 is just equal to 9, causing the 9 branch to be hit. That loses the expression per se, picking up just the evaluation... which we want.
That's the idea. In practice, this requires a fair amount of code; fortunately, boost's preprocessor library already has it done for you, so here are two approaches using boost:
Approach 1: Using Boost Slots
include_counter.h:
#include <boost/preprocessor/slot/slot.hpp>
#if !(INCLUDE_COUNT)
# define INCLUDE_COUNT 0
# define BOOST_PP_VALUE INCLUDE_COUNT
# include BOOST_PP_ASSIGN_SLOT(1)
# undef BOOST_PP_VALUE
# undef INCLUDE_COUNT
# define INCLUDE_COUNT BOOST_PP_SLOT(1)
#endif
#define BOOST_PP_VALUE 1+INCLUDE_COUNT
#include BOOST_PP_ASSIGN_SLOT(1)
Boost slots evaluate macros and store their results using special internal states. You get 5 slots (code above is using slot 1), so you can store 5 numbers. This solution just initializes the slot to 0 before incrementing on the first include, then essentially just increments.
Approach 2: Use Boost Counter
include_counter.h:
#if !(INCLUDE_COUNT)
# include <boost/preprocessor/slot/counter.hpp>
# define INCLUDE_COUNT BOOST_PP_COUNTER
#endif
#include BOOST_PP_UPDATE_COUNTER()
Same idea, though it "consumes" boost counter.
Both boost solutions take the approach I just described. There's also a boost increment macro; feel free to ignore that, since (a) you're evaluating anyway, and (b) boost increment is a bit whimpy (with its maximum limit of 256).
You can also roll your own solution. But when you're done, it's going to look similar to boost's solution anyway. (The advantage is, your new "slot" will be independent of boost counter and boost slots).
An alternative is not to use the macros but the compiler. Many compilers have a "show includes" flag. For instance, in gcc, it is -H. For visual studio, it is /showincludes. Just pipe the compiler output to a file and count the number of lines.
# linux
gcc -H ... fred.c 1> incs.txt 2>&1
wc -l incs.txt
rem Windows
cl /showincludes ... fred.c 1> incs.txt 2>&1
find /v /c "" < incs.txt
# powershell
cl /showincludes ... fred.c 1> incs.txt 2>&1
get-content incs.txt | measure-object -l
Note that this will count the same file if it has been included multiple times, even though it does not get processed because of the guards.

Where the "BYTE_ORDER" macro is defined in OSX?

I want use "BYTE_ORDER" macro in my Xcode project but i can't because i don't know in which header it's defined.
When I look in my Xcode 4.3.X installation, I find the "byte_order.h" file located in a few places:
[/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform]:;!fi
find . -name byte_order.h -print
./Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/architecture/byte_order.h
./Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/machine/byte_order.h
./Developer/SDKs/MacOSX10.6.sdk/usr/include/architecture/byte_order.h
./Developer/SDKs/MacOSX10.6.sdk/usr/include/architecture/i386/byte_order.h
./Developer/SDKs/MacOSX10.6.sdk/usr/include/architecture/ppc/byte_order.h
./Developer/SDKs/MacOSX10.6.sdk/usr/include/machine/byte_order.h
./Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/architecture/byte_order.h
./Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/machine/byte_order.h
./Developer/SDKs/MacOSX10.7.sdk/usr/include/architecture/byte_order.h
./Developer/SDKs/MacOSX10.7.sdk/usr/include/architecture/i386/byte_order.h
./Developer/SDKs/MacOSX10.7.sdk/usr/include/machine/byte_order.h
You'd probably want to do a "#include <architecture/byte_order.h>" in your .c file in order to pick up the byte_order macros.
For the actual "BYTE_ORDER" define itself, well that's defined in a few specific places but the way it's defined seems meant for very specific purposes. For example, this define:
#define __DARWIN_BYTE_ORDER __DARWIN_LITTLE_ENDIAN
#define BYTE_ORDER __DARWIN_BYTE_ORDER
./Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/i386/endian.h
is meant only for Kernel Extensions (drivers).
And this define:
# define BYTE_ORDER LITTLE_ENDIAN
# define BYTE_ORDER BIG_ENDIAN
# endif /* BYTE_ORDER */
# define X_BYTE_ORDER BYTE_ORDER
./Developer/SDKs/MacOSX10.7.sdk/usr/X11/include/X11/Xarch.h
is meant for X11 stuff (ewww).
I'd say the best thing to do is use the "NXHostByteOrder" inline function in the "byte_order.h" file, and this will give you the byte order of the current host.

Resources