Prevent Doxygen from carrying out conditional compilation (compiler-intrinsic defines) - c-preprocessor

I have a lot of code doing conditional compilation based on defines that come from the compiler, not any definitions in the code itself or external headers. For example, quite frequently I have things such as:
#if defined _MSC_VER || defined __ICL
// A lot of freakin code
#elif defined __GNUC__ || defined __ICC
// A bunch more here
#else
#error "Unsupported environment"
#endif
I need to generate documentation for all the code inside the platofm/compiler-specific sections, but I cannot simply set ENABLE_PREPROCESSING to NO because it must be YES for INCLUDE_GRAPH and INCLUDED_GRAPH to work, according to the documentation.
So, how do I do this?

You'd first have to define a macro DOXYGEN or similar in the "predefined" section of the doxygen configuration. Then you'd have to split up the #elif in separate #if and keep track of the fact that you found one valid configuration.
#if defined _MSC_VER || defined __ICL || defined DOXYGEN
#define WE_FOUND_SOME
// A lot of freakin code
#endif
#if defined __GNUC__ || defined __ICC || defined DOXYGEN
#define WE_FOUND_SOME
// A bunch more here
#endif
#ifndef WE_FOUND_SOME
# error "Unsupported environment"
#endif
But beware that if these different parts define the same functions or macros, that doxygen will easily get lost.

Related

Workaround for "semicolon in global scope" warning for no-op C macro

In a codebase that can be built as either C or C++, I thought I'd make a macro to take advantage of static_assert in the case it's built as C++11 or higher.
(Note: I know there are ways to do this in pre-C11 C, at least if you're willing to take a message parameter--though it won't work quite everywhere. But for the sake of argument let's say I have some legitimate need to make it take no message, and be a no-op in at least some C builds.)
So here was the simple definition I tried:
#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond) \
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond)
#endif
There's no semicolon in the macro, with the intent that you would add it at the callsite. But under pedantic C warning settings, this macro appearing in global scope causes:
error: ISO C does not allow extra ‘;’ outside of a function [-Werror=pedantic]
The easy solution seems to be to take the semicolon off the callsites, and put it in the C++11 side of the macro. But I wonder: how do you make a no-op macro in global scope which allows a semicolon at the callsite (without running afoul of some other warning)?
Since forward declarations of structures may be repeated as much as we want, you can use a dummy declaration:
#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick
#JonathanLeffler says this should work in older compilers, even pre-C11...but:
"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"
For related situations that might not be entirely no-ops at compile-time, C11 introduced the ability to repeat typedefs. And as in the post linked about static asserts in C prior to _Static_assert() shows, there are ways to get around typedef duplication for older C using the line number or another disambiguator:
/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b
#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond) \
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif
So long as static assertions appear one per line the identifiers won't conflict with each other.

Doxygen Document All Conditional Defines

I have a project where I have a substantial amount of conditional defines for making cross platform development easier. However I'm having issues convincing Doxygen to extract all the defines, as it will only pick up ones that only happened to evaluate.
For example in the following snippet, Doxygen will document TARGET_X86_64 but not TARGET_ARM64.
#if defined(_M_ARM64) || defined(__arm64__) || defined(__aarch64__)
/** Build target is ARM64 if defined. */
#define TARGET_ARM64
#else
/** Build target is x86_64 if defined. */
#define TARGET_X86_64
#endif
Enabling EXTRACT_ALL did not help, and disabling preprocessing causes Doxygen to not document anything at all. How do I get doxygen to extract documentation for both cases?
I made a "solution" that's verbose, but works. It's less awkward when you want to have #elseif statements than using just using pure #if statements. Although either would work.
First, define everything and not care about conditional logic.
/** Some define */
#define TARGET_DEFINE
/** Some other define */
#define OTHER_TARGET_DEFINE
Second, take the conditional logic that you originally used to create the defines and transform it to undefine logic.
#if !(ORIGINAL_LOGIC)
#undef TARGET_DEFINE
#endif
Lastly, change the conditional logic so that nothing is undefined when doxygen is doing the preprocessing.
#if !defined(DOXYGEN)
...

How to #ifdef by CompilerType ? GCC or VC++

I used #ifdef Win32 for safe calls alike sprintf_s but now I want to build project with MinGW and it's just wrong now. I need to use #ifdef VC++ or somehow like that. Is it possible?
#ifdef __clang__
/*code specific to clang compiler*/
#elif __GNUC__
/*code for GNU C compiler */
#elif _MSC_VER
/*usually has the version number in _MSC_VER*/
/*code specific to MSVC compiler*/
#elif __BORLANDC__
/*code specific to borland compilers*/
#elif __MINGW32__
/*code specific to mingw compilers*/
#endif
See the "Microsoft-Specific Predefined Macros" table of Visual C predefined macros
You could check for _MSC_VER.
Preferably, you should resort to using portable symbols. I understand sometimes those symbols may not be defined, so you can see the Predef project for an extensive list of preprocessor macros regarding standards, compilers, libraries, operating systems and architectures that aren't portable.
However, the function you specifically mention in this question has been included within the C11 standard as a part of Annex K.3, the bounds-checking interfaces (library).
K.3.1.1p2 states:
The functions, macros, and types declared or defined in K.3 and its subclauses are declared and defined by their respective headers if __STDC_WANT_LIB_EXT1__ is defined as a macro which expands to the integer constant 1 at the point in the source file where the appropriate header is first included
Thus, you should place preference upon checking __STDC_WANT_LIB_EXT1__, and only use compiler-specific symbols when that doesn't exist.

what does #ifndef _WIN32 signify? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
the role of #ifdef and #ifndef
Does
#ifndef _WIN32
instruct the cpp to omit the code for 32 bit windows platform ?
#ifndef _WIN32 tells the pre-processor to include the code below it till a corresponding #endif, if _WIN32 is not defined.
#ifndef _WIN32
#define STR1 "Some String"
#endif
The macro STR1 will get included if _WIN32 is not defined and will not get included if _WIN32 is defined. Please note that _WIN32 is a system defined macro. Generally, the code which is not meant for Windows platform or which is generic and cannot be compiled in Windows is placed under such #ifndef _WIN32 macros.
The MSDN page says _WIN32 will be defined by default for all 32 bit and 64 bit builds.
This directive means "don't include this code when _WIN32 macro defined".
If you define macro _WIN32 only when compile for the Win32 then this code "instruct the cpp to omit the code for 32 bit windows platform".
Well it is a preprocessor directive. It is called compilation constants.
Compiler will consider the piece of code under those #ifndef if the compilation constant(such as, _WIN32) is not defined.
I believe above explanation will help you resolving your query.
To be more specific,
#ifndef _WIN32
...
...
...
some code
...
...
...
#endif
here if you have not defined _WIN32 (such as #define _WIN32) then the code within that #if...#endif will be compiled.
hope it helps.

C: How to conditionally compile certain parts of code based on Compiler Type?

I would like to conditionally compile certain parts of code based on Compiler Type is there any macro for that?
Like this:
#if defined (COMPILER_TYPE e.g. GCC)
// Compile this
#elif defined (COMPILER_TYPE e.g. Visual Studio C Compiler)
// Else this
#endif
Thank you
You can check if these macros are defined, __GNUC__ for GCC and _MSC_VER for MSVC.

Resources