【问题标题】:-Werror causes compiler to stop on #warning. What can I do to prevent this?-Werror 导致编译器在#warning 时停止。我能做些什么来防止这种情况发生?
【发布时间】:2011-05-21 06:42:50
【问题描述】:

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

很遗憾,我的编译器不支持#info#message#pragma message()等。

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

有什么建议吗?

不管怎样,我正在使用 Tensilica Xtensa 编译器 xt-xcc,它似乎是 GNU 的衍生产品,或者至少使用了 GNU 前端。它是 8.0.0 版。

【问题讨论】:

  • 您使用的是什么编译器和版本?
  • 既然您说它是 GNU 衍生产品:gcc 的 -fdiagnostics-show-option 选项告诉它告诉您哪个选项控制发生的每个警告。也许 xt-xcc 有那个?
  • 另一种选择是(非常丑陋)将所有其他警告单独转换为错误。
  • @JXG:除了问题不是特定于“嵌入式”并且通常适用于 GCC。不确定它是否证明了嵌入标签的合理性。
  • -Wno-error=cpp 适用于我的 gcc 4.6.1 版(请参阅我的答案)。较新的 gcc 可以优雅地命名警告的类别名称... :-)

标签: c gcc embedded c-preprocessor preprocessor-directive


【解决方案1】:

如果您的编译器支持它,您可以尝试使用constructor function attribute 来定义一个在程序启动时(main 之前)运行的函数,该函数会向标准输出打印一条消息:

#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

这会导致在运行时而不是编译时打印出一条消息,这几乎一样好,尤其是在您没有其他选择的情况下。唯一的限制是您必须在函数定义之外的全局范围内使用 this。

【讨论】:

  • 这是一个嵌入式项目,没有控制台,也没有屏幕。
【解决方案2】:

有什么问题:

#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”编译,但某些文件可能有例外,允许特定类型的 警告。或者,项目可能会选择性地启用诊断并将其视为错误,具体取决于 在其上定义了预处理器宏。

#pragma GCC diagnostic kind option

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

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

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

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

#pragma message string

在编译时将字符串打印为编译器消息。该消息是信息性的 只是,既不是编译警告也不是错误。

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

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

我不确定您是否愿意将您的 #warning 行编辑为 #pragma message 行。它可以帮助您解决问题 - 并且只比在 #warning 周围添加条件编译更糟糕,因为 #pragma message 可能会被更少的编译器支持。这取决于您的可移植性要求。

【讨论】:

  • 问题的症结在于#warning 会导致编译在命令行中出现-Werror 时停止,我不知道除了删除-Werror 之外如何覆盖它,这不是一个选项.
  • 您希望警告成为错误,除非它们本来应该是警告?棘手……如果不矛盾的话。
  • 好吧,我希望警告是错误的,除了这个(或这个类的)。我只是不知道要传递给 -Wno-error=????不要将#warning 视为错误。或者我想要提供#message 或#pragma message() 或类似内容的工具。
  • 我认为当前的 GCC 代码库不可能做到这一点。 -Werror 使任何来源的任何警告都变成错误(正如您所知道的那样),并且没有办法避免这种 AFAIK。你将不得不放弃你的#warnings,或者用#ifdef DO_WARNINGS / #warning "Some warning" / #endif保护它们
  • -Wno-error=implicit,例如,即使存在 -Werror,也不会将“隐式函数调用”警告视为错误。我希望互联网的集体知识会知道描述“#warning”警告类别的神奇咒语,所以我可以像其他类别的警告一样关闭它。
【解决方案3】:

很遗憾,我的特定工具链没有答案,Tensilica 的工程师们是这么说的。他们不支持#message 或#pragma message(),也不知道如何在-Werror 存在时将#warning 抑制为错误。

GCC 工具链允许使用 -Wno-error=[code] 来表示“此警告不是错误”,但我没有找到与 #warning 对应的列表这将需要的代码(甚至可能是代码列表)。

我可能会尝试抽出时间深入研究标准 GCC 命令行和预处理器源代码,以尝试找到 -Wno-error= 可以等于的列表,或者是否存在 -Werror = 对应于#warning 的代码。

【讨论】:

    【解决方案4】:

    假设 #warning 可能由预处理器处理,您可以在没有 -Werror 的情况下单独运行预处理器,然后在预处理器输出上禁止预处理的情况下运行编译器。

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

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

    【讨论】:

    • 我选择了同样的路线。我的目标不是零警告。目标是只有#warning-directive 生成​​的警告,并且足够少,您不必滚动阅读它们。这适用于一个 +100KLOC 大小的商业项目,有四五个人合作。用 C 编写的嵌入式实时代码。
    【解决方案5】:

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

      #pragma GCC diagnostic warning "-Wcpp"
    

    使#warning 成为一个简单的警告问题(不是因为-Werror 而导致的错误)。为了使效果暂时,您可以在#pragma GCC diagnostic push#pragma GCC diagnostic pop 之间使用#pragma#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),我得到以下输出:

    ```lang-none
    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 的错误和在满足您的要求之后立即恢复设置似乎是更准确的方法。

    使用 GCC 版本 4.8.4 和 4.9.2 给出了几乎相同的行为(仅额外打印了源代码行)。但使用 GCC 版本 5.0.1(Ubuntu 15.04 (Vivid Vervet) 中包含的预发布版本)会给出两个警告,除非还包含选项 -Werror=cpp。因此,带有较新 GCC 的 -Werror 似乎不再像以前那样暗示 -Werror=cpp,如果需要,需要单独提供。

    【讨论】:

    • 赞成,但上面的 sn-p 对我来说仍然失败(使用 gcc 4.8.4)
    • @M2X - 如何失败?您需要包含选项-c(仅编译);否则gcc 会尝试链接,但由于缺少功能main() 我猜它会失败。我用gcc 4.8.4 和 4.9.2 进行了测试,自从我最初写这个答案以来,基本上没有任何改变。但是使用 gcc 5.0 -Werror 不再暗示 -Werror=cpp
    • @FooF 我应该更清楚。我不是在谈论您上面的示例 sn-p(带有main)。我正在一个启用了-Werror 的大型项目中工作。我试图让 gcc 忽略某些 Qt 标头中的一些 #warnings。当我在包含这些标头之前添加#pragma GCC diagnostic warning "-Wcpp" 时,当编译器到达#warning 行时,我仍然收到错误(而不是警告)...有什么想法吗?
    • @M2X - 你的gcc 是否像上面描述的那样工作?我没有时间调查您的问题,但是您是否尝试过(推送或全部)#pragma GCC diagnostic 事情在#include 期间以某种方式重置?否则,如果您不想在遇到其他不应该存在的 #warnings 时停下来,也许您可​​以考虑将 -Eno-error=cpp 添加到编译器标志中。当然,您也可以查看 GCC 文档以获取有关 #pragmathingelings 的更多信息。
    【解决方案6】:

    十年后,发出警告并避免来自 -Wpedantic 的这些额外消息/错误的正确方法是使用 #pragma message。 GCC 至少从 GCC 4.5 开始支持这种语法,从至少 Clang 6 开始支持 Clang。

    这些编译器的现代版本甚至支持#pragma GCC error "message"#pragma GCC warning "message"GCC 9,Clang 6 已经支持)。

    【讨论】:

    • 我发现#pragma GCC warning "message" 仍在触发错误。
    • 也许你正在传递-Werror。而且由于您没有指定 GCC 版本,因此很难知道您遇到了什么问题。
    • 我正在传递-Werror,这就是最初的问题。
    猜你喜欢
    • 1970-01-01
    • 2019-10-05
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多