如何记录未定义的预编译标志

How to document undefined precompilation flags

我有要使用 doxygen 记录的 C 代码。 C代码是一个代码块,可以被不同的应用程序取用。在编译时,这些应用程序通过定义特定的宏(或通过 而不是 定义它们)来改变代码块的功能。

例如拿这个文件,block.c:

int Block_DoPlus(int x, int y)
{
#if defined(DO_EXTRAPLUS)
    return x + y + y;
#else
    return x + y;
#endif
}

int Block_DoMinus(int x, int y)
{
#if defined(DO_EXTRAMINUS)
return x - y - y;
#else
return x - y;
#endif
}

记录这些未定义的预编译标志 DO_EXTRAPLUSDO_EXTRAMINUS 的最佳方法是什么?


选项 1block.h - 不起作用DO_EXTRAPLUSDO_EXTRAMINUS 不显示在生成的 html

#ifndef __BLOCK_H__
#define __BLOCK_H__
/** @defgroup BLOCK A block of code
 * gcc this code with -dDO_EXTRAPLUS and/or -dDO_EXTRAMINUS
 * @{
 */

/** Does extra plus */
#ifndef DO_EXTRAPLUS
#   undef DO_EXTRAPLUS
#endif

/** Does extra minus */
#ifndef DO_EXTRAMINUS
#   undef DO_EXTRAMINUS
#endif

/** Does plus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoPlus(int x, int y);

/** Does minus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoMinus(int x, int y);
#endif /** @} */

选项 2block.h - 有效,但代码看起来很愚蠢

#ifndef __BLOCK_H__
#define __BLOCK_H__
/** @defgroup BLOCK A block of code
 * gcc this code with -dDO_EXTRAPLUS and/or -dDO_EXTRAMINUS
 * @{
 */

/** Does extra plus */
#ifndef DO_EXTRAPLUS
#   define DO_EXTRAPLUS
#   undef DO_EXTRAPLUS
#endif

/** Does extra minus */
#ifndef DO_EXTRAMINUS
#   define DO_EXTRAMINUS
#   undef DO_EXTRAMINUS
#endif

/** Does plus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoPlus(int x, int y);

/** Does minus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoMinus(int x, int y);

#endif /** @} */

选项 3block.h - 有效,但在 html 文件中看起来很愚蠢,而且你可以稍后使用 ::(或 #)引用 DO_EXTRAPLUS,仅使用 \ref

#ifndef __BLOCK_H__
#define __BLOCK_H__
/** @defgroup BLOCK My fancy block of code
 * gcc this code with -dDO_EXTRAPLUS and/or -dDO_EXTRAMINUS
 * 
 * @anchor DO_EXTRAPLUS
 * @par #define DO_EXTRAPLUS
 *  Does plus
 *  
 * @anchor DO_EXTRAMINUS
 * @par #define DO_EXTRAMINUS
 *  Does minus
 * @{
 */

/** Does plus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoPlus(int x, int y);

/** Does minus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoMinus(int x, int y);

#endif /** @} */ 

选项 4: ???

我会选择选项 0:不使用编译器标志进行配置。改用全局变量(或者,更好的是,配置对象中的变量)。

  • 编译器标志很难记录,正如您所发现的。

  • 无法在运行时更改编译器标志。

  • 编译器标志在可执行文件中共享。没有(简单的)方法可以让应用程序的一部分使用您的代码和一组编译器标志,而另一部分使用不同的标志。

  • 编译器标志与将代码构建为库不兼容。 (我的意思是,您 可以 将代码构建为库,但是您必须在构建时选择使用哪些标志。库的消费者在这件事上别无选择。)

  • 编译器标志与代码测试不兼容:

    • 大多数测试框架都假定您的代码可以编译一次,然后通过以不同方式调用它来进行测试——当您的部分代码只有在使用某些编译器标志构建时才能访问时,这就变得不可能了。

    • 即使您的代码具有中等数量的编译器标志,也无法测试所有组合。您最终会遇到某些标志集可能永远不会被测试的情况,并且可能会由于不同条件启用的代码块之间的意外交互而导致意外行为(甚至编译失败!)。

我找到的最佳解决方案:

选项 4block.h - 有效,在代码和 html[= 中看起来都不错16=]

#ifndef __BLOCK_H__
#define __BLOCK_H__
/** @defgroup BLOCK A block of code
 * @{
 */

/* Flags below are undefined by default.
 * They are wrapped in a DOXYGEN precompilation flag to enable
 * documenting them properly.
 */
#ifdef __DOXYGEN__
#error This block of code may not be parsed using gcc.

/** Does extra plus */
#define DO_EXTRAPLUS When defined, changes behavior of Block_DoPlus

/** Does extra minus */
#define DO_EXTRAMINUS When defined, changes behavior of Block_DoMinus

#endif

/** Does plus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoPlus(int x, int y);

/** Does minus
 * @param x : x is ickx
 * @param y : y is why
 */
int Block_DoMinus(int x, int y);

#endif /** @} */

Plus,在您的 doxyfile

中添加 __DOXYGEN__ 作为预定义宏
  • 可以使用 ::(或 #
  • 引用标志
  • 标志与其他令牌一样被记录在案
  • 解析define后的文本并链接识别的token
  • #error 指令和非 doxygen 注释给出了结构的清晰解释