【问题标题】:How to set warning level in CMake?如何在 CMake 中设置警告级别?
【发布时间】:2011-01-23 01:15:44
【问题描述】:

如何使用CMake项目(不是整个解决方案)设置警告级别?应该在 Visual StudioGCC 上工作。

我找到了各种选项,但大多数似乎要么不起作用,要么与文档不一致。

【问题讨论】:

    标签: cmake warning-level


    【解决方案1】:

    在现代 CMake 中,以下内容运行良好:

    if(MSVC)
      target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX)
    else()
      target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror)
    endif()
    

    我的同事建议了一个替代版本:

    target_compile_options(${TARGET_NAME} PRIVATE
      $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
      $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>
    )
    

    ${TARGET_NAME} 替换为实际的目标名称。 -Werror 是可选的,它将所有警告变成错误。

    如果您想按照 @aldo 在 cmets 中的建议将其应用于所有目标,请使用 add_compile_options(...)

    另外,请务必了解PRIVATEPUBLIC 之间的区别(公共选项将由依赖于给定目标的目标继承)。

    【讨论】:

    • 如果您想将其应用于所有目标,则只需 add_compile_options(...)
    • 仅供参考,现代 CMake 不需要重复 else()endif() 中的条件。
    • @Timmmm 感谢您的提醒!它只是一个注释还是您希望我删除条件?
    • @helmesjo 不,Timmmm 指的是在 4 月 9 日编辑之前存在的 CMake 代码。您可以查看编辑历史记录以查看已删除的位,这与 Timmmm 指出的相同。
    • @aldo add_compile_options() 的问题是警告将传播到通过add_subdirectory() 添加的目标。如果您以这种方式包含外部库,如果该库被设计为具有不同的警告级别,您可能会收到大量警告。
    【解决方案2】:

    更新:这个答案早于现代 CMake 时代。每个理智的 CMake 用户都应该避免直接摆弄CMAKE_CXX_FLAGS,而是调用target_compile_options 命令。查看提供推荐最佳实践的mrts' answer

    你可以做类似这样的事情:

    if(MSVC)
      # Force to always compile with W4
      if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
        string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
      else()
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
      endif()
    elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
      # Update if necessary
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
    endif()
    

    【讨论】:

    • 请注意,新版本的 Visual Studio(至少 2013 年)支持 /Wall 标志(名为 EnableAllWarnings)。它产生的警告比/W4 还要多。但是根据我的经验,它会产生太多警告。
    • /Wall 可以用于如果您想遵循警告的“减法”策略,就像 clang 的 -Weverything。您无需选择要启用的警告,而是启用所有内容,然后选择要禁用的特定警告。
    【解决方案3】:

    一些CMake modules I've written 包括实验性cross-platfrom warning suppression

    sugar_generate_warning_flags(
        target_compile_options
        target_properties
        ENABLE conversion
        TREAT_AS_ERRORS ALL
    )
    
    set_target_properties(
        foo
        PROPERTIES
        ${target_properties}
        COMPILE_OPTIONS
        "${target_compile_options}"
    )
    

    Xcode 的结果:

    • 设置CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSIONXcode 属性 (又名 构建设置 -> 警告 -> 可疑的隐式转换 ->
    • 添加编译器标志:-Werror

    Makefile gcc 和 clang:

    • 添加编译器标志:-Wconversion-Werror

    视觉工作室:

    • 添加编译器标志:/WX/w14244

    链接

    【讨论】:

    • 很遗憾 cmake 没有提供这个功能
    • 好消息。很抱歉在这里而不是在 cmake 邮件列表中发布它,但是没有级别这将是无用的,有太多警告要明确列出它们。如果您想统一它,一种方法是使用两个单独的 cmake_level - 统一的警告集,例如基于 clang,以及具有特定于编译器含义的 native_level。其中之一可能会缩短到水平。抱歉,如果我没有真正关注对话并出现问题
    • @void.pointer 提出了一个有效点。您提出的答案是:计划添加此功能”。这并不是说您做了一些粗略的研究,现在希望其他人为您完成繁重的工作。如果您不想被归因于实施(以及有关其进度的问题),您需要编辑您的答案,并将自己与一年多来没有取得任何进展的任务分离。
    • “一年多过去了,仍然没有进展。” - 现在一个有效点。一年多过去了,进展。这是一个被放弃的项目的一个非常强烈的迹象。如果您想证明我们错了,请向我们展示一些进展。这还没有发生,但您提出的答案仍然表明,该功能即将添加到 CMake。为什么要对多年后无法使用的功能大惊小怪?这根本没有帮助。要么显示一些进展,要么编辑你的答案以减少误导。
    • 你似乎不明白。如果你建议你要实现一个特性,那么你需要在适当的时候实现那个特性。否则,您将被要求从您提出的答案中删除该承诺。您已表现出对实施所述功能的零承诺,因此请勿另行声明。我知道它很大。我也明白你可能无法做到这一点。我只是要求你让你的回答反映出这一点。
    【解决方案4】:

    根据Cmake 3.23 documentation

    if (MSVC)
        # warning level 4 and all warnings as errors
        add_compile_options(/W4 /WX)
    else()
        # lots of warnings and all warnings as errors
        add_compile_options(-Wall -Wextra -pedantic -Werror)
    endif()
    

    GCC 和 Clang 共享这些标志,因此这应该涵盖所有 3 个。

    【讨论】:

    • 不要使用这个。相反,使用 target_compile_options()。引用最新的文档似乎是“正确的”,但它是一个古老的条目,仅仅是为了向后兼容。
    • @caoanan 文档没有提到向后兼容性。 add_compile_options 是目录范围的,而 target_compile_options 仅适用于单个目标。
    【解决方案5】:

    这是迄今为止我找到的最佳解决方案(包括编译器检查):

    if(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
        add_definitions(/W2)
    endif()
    

    GCC 等价物是 -Wall(未经测试)。

    【讨论】:

    • GCC 的警告标志将是 -Wall 并且可能是 -Wextra,详见 gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
    • 我使用的列表是-W -Wall -Wextra -pedantic-Wextra IIRC 在更高版本的 GCC 中替换了 -W,但出于兼容性考虑,我将两者都保留了。
    • 这不是add_definitions 的预期目的(“它旨在添加预处理器定义”)。这也不仅仅是最佳实践建议。传递给此命令的参数将显示在生成的构建脚本中调用不期望它们的工具(例如资源编译器)。
    • 这不是“编译器检查”,而是构建工具检查。
    【解决方案6】:
    if(MSVC)
        string(REGEX REPLACE "/W[1-3]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    endif()
    

    如果你使用target_compile_options - cmake 将尝试使用双/W* 标志,这将由编译器发出警告。

    【讨论】:

    • 谢谢。我天真地使用add_compile_options 只是为了得到大量警告/W3/W4 覆盖。 CMake 没有解决这个基本选项(设置警告级别)的事实令人难以置信。
    【解决方案7】:

    如何使用 CMake 为项目(不是整个解决方案)设置警告级别?

    (我认为这是指a CMake target,而不是a CMake project。)

    我找到了各种选项,但大多数似乎要么不起作用,要么与文档不一致。

    Kitware 的 API 可能会阻止您使构建系统变得脆弱和容易出错。这个问题的其他答案所鼓励的特殊情况至少违反了现代 CMake 构建系统的两个重要原则......

    首先,更喜欢 not 在 CMakeLists.txt 文件中指定工具链特定的详细信息。它使构建系统变得脆弱。例如,如果工具链的未来版本中出现新警告,编译器将发出错误,您的用户可能需要破解您的项目才能构建目标。

    改为编写与工具链无关的 CMakeLists.txt 文件,并保留用户在他们认为合适时进行自定义的能力。理想情况下,您的项目应该使用 vanilla 工具链配置在任何地方构建 - 即使默认情况下不会启用您首选的警告。

    其次,如果您打算将二进制文件链接在一起,标志应该是一致的。这降低了可能导致程序格式错误的不兼容风险。但是,警告标志不太可能影响代码生成,因此可能在链接在一起的目标之间改变这些标志是安全的。

    所以...如果您希望为每个工具链指定标志,并且如果您绝对必须为不同的目标设置不同的标志,请使用自定义变量:

    # CMakeLists.txt
    project(my_project)
    
    add_executable(my_target source_file.cpp)
    target_compile_options(my_target PRIVATE "${MY_PROJECT_ELEVATED_WARNING_FLAGS}")
    

    有很多方法可以设置这些变量,例如 CMakeCache.txt、a toolchain file 和通过CMAKE_PROJECT_INCLUDE_BEFORE。但最简单的方法是在配置过程中在命令行上,对于 GCC

    cmake -DMY_PROJECT_ELEVATED_WARNING_FLAGS:STRING="-Wall;-Wextra;-Wpedantic;-Werror" <path-to-project>
    

    对于 MSVC

    cmake -DMY_PROJECT_ELEVATED_WARNING_FLAGS:STRING="/W4;/WX" <path-to-project>
    

    【讨论】:

      猜你喜欢
      • 2017-09-05
      • 2020-10-07
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      • 2011-04-15
      • 2013-01-16
      • 2014-10-23
      相关资源
      最近更新 更多