-Werror导致编译器在#warning上停止。 我该怎么做才能防止这种情况发生?

首先,我希望它停止警告。 但我也希望打印出一些信息性的消息(比如“回来实现这个!”)。

不幸的是,我的编译器不支持#info #message#pragma message()#pragma message()等。

我知道有-Wno-error= ,但我的google-foo很弱,我似乎无法找到#warning 。 我试过-Wno-error=warning ,只是说“没有 – -Wwarning ”。 与“ warn ”相同。

有什么建议?

值得一提的是,我使用的是Tensilica xtensa编译器,xt-xcc,它似乎是一个gnu派生词,或者至少使用了gnu前端。 它的版本是8.0.0。

我不熟悉Tensilica xtensa编译器( xt-xcc ),但您可以使用标准gcc

  #pragma GCC diagnostic warning "-Wcpp" 

使#warning成为简单警告的问题(因为-Werror而不是错误)。 要使效果暂时,您可以使用#pragma#pragma GCC diagnostic push#pragma GCC diagnostic pop之间的#warning

当我编译包含以下内容的文件时

  #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wcpp" #warning one #pragma GCC diagnostic pop #warning two 

使用-Werror使用gcc 4.6.1(命令gcc -c -Werror warning-test.c ),我得到以下输出:

  warning-test.c:3:2: warning: #warning one [-Wcpp] warning-test.c:6:2: error: #warning two [-Werror=cpp] cc1: all warnings being treated as errors 

当我删除第二个#warning ,编译不会被错误中断。

您还可以使用-Werror -Wno-error=cpp替换-Werror编译器选项。 我不知道cpp类别的警告包含哪些其他影响(并且您可能在其他某个地方有一个合法的#warning要捕获为错误),因此暂时禁用特定#warning的错误并立即恢复设置似乎更准确的方法满足您的要求。

编辑(2016):使用gcc版本4.8.4和4.9.2给出了几乎相同的行为(仅额外打印源行)。 但是使用gcc版本5.0.1(Ubuntu 15.04中包含的预发布版本)将提供两个警告,除非包含选项-Werror=cpp 。 所以似乎 – 更新gcc的错误不再像以前那样暗示-Werror=cpp ,如果需要它需要单独提供。

出了什么问题:

 #warning "Come back and implement this" #warning "Do not do that!" #warning "Must fix this before release" 

通常,编译器会在错误或警告消息中包含参数 – 或者在#warning之后的材料。

而且,通常情况下,如果编译器检测到需要警告的内容,它会相当清楚地报告。


鉴于这些要求,我认为解决这个问题的唯一方法是保护#warning指令……

 #ifdef DO_WARNINGS #warning "Some warning" #endif /* DO_WARNINGS */ 

大多数情况下,编译时不使用-DDO_WARNINGS ; 当你需要检查#warning警告(使用-Werror )时,你会包含-DDO_WARNINGS ,接受编译失败。 请记住,即使存在单个编译错误, make -k也会尽可能多地执行。


GCC 4.4.1手册第5.52.9节(部分)说:

5.52.9诊断编译

GCC允许用户有选择地启用或禁用某些类型的诊断,并更改诊断的类型。 例如,项目的策略可能要求所有源使用“-Werror”进行编译,但某些文件可能具有允许特定类型警告的exception。 或者,项目可以选择性地启用诊断并将其视为错误,具体取决于定义的预处理器宏。

 #pragma GCC diagnostic kind option 

修改诊断的处置。 请注意,并非所有诊断都可以修改; 目前只有警告(通常由’-W ……’控制)可以控制,而不是所有警告。 使用’-fdiagnostics-show-option’确定哪些诊断可控,哪个选项控制它们。 kind是’错误’将此诊断视为错误,’警告’将其视为警告(即使’-Werror’有效),或者如果要忽略诊断则’忽略’。 option是双引号字符串,与命令行选项匹配。

 #pragma GCC diagnostic warning "-Wformat" #pragma GCC diagnostic error "-Wformat" #pragma GCC diagnostic ignored "-Wformat" 

请注意,这些编译指示会覆盖任何命令行选项。 此外,虽然将这些编译指示放在源中的任何位置在语法上是有效的,但它们唯一受支持的位置是在定义任何数据或函数之前。 否则可能会导致不可预测的结果,具体取决于优化程序管理源的方式。 如果多次列出相同的选项,则指定的最后一个选项是有效的选项。 此pragma不是用于命令行选项的通用替代,而是用于实现对项目策略的严格控制。

GCC还提供了一种在编译期间打印消息的简单机制。

 #pragma message string 

在编译时将字符串打印为编译器消息。 该消息仅供参考,既不是编译警告也不是错误。

 #pragma message "Compiling " __FILE__ "..." 

字符串可以用括号括起来,并打印出位置信息。

我不确定您是否想将#warning行编辑成#pragma message行。 这会让你解决问题 – 而且只比在#warning中添加条件编译更糟糕的是, #pragma message可能会被更少的编译器支持。 这取决于您的可移植性要求。

鉴于#warning大概是由预处理器处理的,你可以在没有-Werror的情况下单独运行预处理器,然后运行编译器,在前处理器输出上禁止预处理。

为此,通过预处理器运行带有除-Werror之外的所有常规选项的.c文件,并将输出生成为.i文件(.ii for C ++)。 编译器将这些文件识别为不进行预处理,因此您可以使用-Werror编译它们,并假设预处理器丢弃#warning并且编译器本身不处理它,这可能会解决您的问题。

我没有测试过这个; 当我遇到同样的问题时,我只选择使用它而不是使用-Werror。 解决方案似乎比问题更复杂!

如果您的编译器支持它,您可以尝试使用constructor函数函数属性来定义在程序启动时(在main之前)运行的函数,该函数将消息打印到stdout:

 #define TOKENPASTE(x, y) TOKENPASTE2(x, y) #define TOKENPASTE2(x, y) x ## y #define WARNING(message) \ static void TOKENPASTE(_print_warning, __LINE__)() __attribute__((constructor)); \ static void TOKENPASTE(_print_warning, __LINE__)() \ { \ puts(message); \ } WARNING("fix this before ship") // prints out a message at runtime before main 

这会导致在运行时而不是编译时打印出消息,这几乎同样好,特别是如果您没有其他选项。 唯一的限制是您必须在函数定义之外的全局范围内使用它。

不幸的是,我的特定工具链没有答案,或者Tensilica的工程师说。 它们不支持#message或#pramga message(),或者知道如何在出现-Werror时将#warning抑制为错误。

GCC工具链允许使用-Wno-error = [code]来说“这个警告不是错误”,但我还没有找到一个列表,它将#warning与任何代码相对应(或者甚至列表这可能是代码)

我可能会试着找时间深入研究标准GCC命令行和预处理器源代码,试图找到-Wno-error =可以等于的列表,或者是否有-Werror =代码对应#warning。 如果我这样做,我会回来更新答案。