【问题标题】:How to suppress Clang warnings in third-party library header file in CMakeLists.txt file?如何在 CMakeLists.txt 文件中的第三方库头文件中抑制 Clang 警告?
【发布时间】:2019-11-04 12:32:15
【问题描述】:

我目前正在尝试使用 Visual Studio 2019 的新 CMake 功能(尤其是将 Clang 和 Ninja 与 CMake 和 VS2019 结合使用)来设置一个使用多个编译器(包括 Clang、MSVC 和 GCC)的项目。

我正在使用 CMake 将项目配置为“与编译器无关”,因此 我不需要通过预处理器指令或 @ 来编辑代码本身来处理不同的编译器 987654324@指令。

此项目需要配置为具有高警告级别(/W4 用于 MSVC,-Wall-Wextra-Wpedantic 用于 Clang),并且必须将警告视为错误。

在配置项目的 MSVC 部分时,我没有任何问题。许多这些设置具有“正常”的默认值,正如我所期望的那样“正常工作”。然而,当谈到 Clang 时,我遇到了一个问题:

我似乎无法禁用第三方库头文件的警告。我目前正在使用Dear ImguiSFML 库。由于 Dear Imgui 没有预编译,我只需在我的 CMakeLists.txt 文件中执行以下操作即可将其包含在内:

include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui
)

我使用 SFML 的静态链接版本,因此我执行以下操作来包含它:

# Find SFML and link statically to it.
# Note: We need to set the SFML_DIR variable manually.
set(SFML_STATIC_LIBRARIES TRUE)
set(SFML_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs/SFML-2.5.1/lib/cmake/SFML")
find_package(SFML 2.5.1 COMPONENTS system audio window graphics REQUIRED)

target_link_libraries(${PROJECT_NAME}
    PRIVATE
        sfml-system
        sfml-audio
        sfml-window
        sfml-graphics
)

遗憾的是,SFML 目前不遵循当前的 CMake 添加库的标准方式,因此通过 CMake 使用或配置它有点奇怪。

现在,当涉及到在我的项目中包含库时,上述方法工作得很好(但这可能是我需要更改的内容,因此我已将其包含在帖子中)。当我在使用 Clang 时尝试将警告和警告作为错误配置强加给他们时,就会出现问题。

以下是我的 CMakeLists.txt 文件中处理 Clang 和我的 C++ 配置的部分:

# Set project to use C++ 17 standard.
set_target_properties(
    ${PROJECT_NAME}
    PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
)


target_compile_options(${PROJECT_NAME} PRIVATE
    # All warnings, warnings as errors, be pedantic.
    -Wall
    -Wextra
    -Werror
    -Wpedantic

    # Disable warnings about C++98 incompatibility. We're using C++17 features...
    -Wno-c++98-compat
    -Wno-c++98-compat-pedantic
)

使用上述配置会导致 Dear Imgui 的源文件中出现数百个警告/错误(由于使用“老式”C++/C 样式代码),以及 SFML 自己的源文件中的一大堆警告/错误文件和头文件。

在确定以下解决方案之前,我一直在寻找解决此问题的方法近一周(这并不完全有效,稍后会详细介绍):

set(LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/libs")
set(IMGUI_FOLDER "${LIBS_FOLDER}/imgui")
set(SFML_FOLDER "${LIBS_FOLDER}/SFML-2.5.1/include/SFML")

file(GLOB LIBRARY_FILES
    # Dear-imgui
    "${IMGUI_FOLDER}/*.cpp"
    "${IMGUI_FOLDER}/misc/freetype/*.cpp"
    "${IMGUI_FOLDER}/misc/fonts/*.cpp"
    "${IMGUI_FOLDER}/misc/cpp/*.cpp"

    # SFML
    "${SFML_FOLDER}/Audio/*.cpp"
    "${SFML_FOLDER}/Graphics/*.cpp"
    "${SFML_FOLDER}/Network/*.cpp"
    "${SFML_FOLDER}/System/*.cpp"
    "${SFML_FOLDER}/Window/*.cpp"
)

set_source_files_properties(
    ${LIBRARY_FILES}
    PROPERTIES
    COMPILE_FLAGS
    "-Wno-everything"
)

我从GLOB-ing 我的库源文件开始(注意:我知道GLOB 通常被看不起,但我觉得将它与第三方库文件一起使用很好,因为它们是无论如何都不应该改变)。然后我将它们传递给set_source_files_properties 函数以应用-Wno-everything 标志,这似乎可以正确地抑制来自这些文件的所有错误和警告。

一切似乎都很好,除了一个警告,如果不在我的代码中使用#pragma 指令(我想避免),我似乎无法禁用它。在编译包含 SFML 标头的空 main 函数时,我收到有关其 .hpp 文件的警告(无法传递给 set_source_files_properties 函数)。

这个:

#include <SFML/Graphics.hpp>

int main()
{
}

导致以下警告/错误:

zero as null pointer constant [-Werror,-Wzero-as-null-pointer-constant]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]

在这些各自的 SFML 文件中:

ThreadLocal.hpp (57)
Keyboard.hpp (161)
Event.hpp (105)
PrimitiveType.hpp (52)

我尝试过的其他方法不起作用:

  • .h/.hpp 文件放入set_source_files_properties CMake 函数(与.cpp 文件一起)。适用于 Dear Imgui,但其所有错误都在 .cpp 文件中,而不是其标题中。不适用于 SFML 的标头。
  • (不适用于 SFML,但适用于 Dear Imgui)将目录包含为 SYSTEM 包括禁止警告。似乎不适用于 Windows。 SFML 无法真正做到这一点,因为我使用的是 CMake 的 find_package 函数,而不是手动执行所有操作。
  • 使用#pragma 指令。虽然这有效,但每个 SFML 文件都有几十个不同的错误,我想避免在任何地方使用#pragmas(或者将 SFML 的标头包装在我自己的标头中,只是将 #include 指令包装在 #pragmas 中)。李>

在没有#pragmas 的情况下,甚至可以为我的库标题抑制这些警告吗?我以前从未真正使用过 Clang,如果这似乎是一个简单的问题,我深表歉意,但在线搜索并没有真正给我任何有用的东西:

  • 在命令行之外(我正在使用带有 CMake 的 Visual Studio)。
  • 在 Windows 上(系统标志似乎不适用于此设置)。
  • 这特别适用于 CMake。

【问题讨论】:

  • 我知道 gcc 并且可能还会禁用系统包含文件的一些警告。因此,如果您使用 -isystem 命令行选项代替 -I 指定标题目录,它应该可以工作。使用 cmake,您可以使用 target_include_directories(&lt;target&gt; SYSTEM &lt;dir&gt;). 指定它
  • @Oliv 如帖子中所述,我不能真正为 SFML 使用 SYSTEM 关键字,因为我自己不包括它的目录​​,我正在使用 find_package 命令,其中包括SFML 目录以自己的方式。
  • 对不起,我没有阅读你所有的长问题。您仍然可以执行 target_include_directories( SYSTEM )。您可以使用 get_property 获取 。 gcc 和可能 clang 也认为使用 -I 和 -isystem 指定的目录是系统目录。
  • @Oliv 刚刚尝试将 SFML 包含目录添加到我的 target_include_directories 函数(使用 SYSTEM 关键字),但它似乎不起作用。我还尝试在 find_packagetarget_link_libraries 函数之前和之后放置函数,但它仍然不起作用。可能是因为警告/错误是头文件本身?
  • 我遇到过这个问题,简短的故事:VS 有一个与-isystem 相当的实验性等效项(参见devblogs.microsoft.com/cppblog/broken-warnings-theory),因此clang-cl 不明确支持它。你仍然可以使用-Xclang -isystem /path/to/libs/imgui 破解它。但是...它似乎有问题,可能导致导入的标头无法编译...您必须自己检查它。 (稍后我会尝试使用一些代码示例将其转换为答案,但我需要查看我正在处理的代码)。

标签: c++ cmake clang suppress-warnings


【解决方案1】:

您可以将包含路径标记为SYSTEM。大多数编译器不会在系统头文件中报告警告。在您的情况下,可能看起来像这样:

include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui)

set_target_properties(sfml-system PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-system,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-audio PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-audio,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-window PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-window,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-graphics PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-graphics,INTERFACE_INCLUDE_DIRECTORIES>)

例如,这个虚拟项目:

project(example)
cmake_minimum_required(VERSION 3.18)

add_library(dep INTERFACE)
target_include_directories(dep INTERFACE include)
file(WRITE include/header.h "static int a;")

add_library(lib STATIC lib.c)
target_link_libraries(lib PRIVATE dep)
target_compile_options(lib PRIVATE -Wunused -Werror)
file(WRITE lib.c "#include <header.h>")

失败:

$ cmake . && make
include/header.h:1:12: error: ‘a’ defined but not used [-Werror=unused-variable]

但是在加入这一行之后:

set_target_properties(dep PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:dep,INTERFACE_INCLUDE_DIRECTORIES>)

它的构建没有错误。

【讨论】:

  • 天哪 - 我已经为此奋斗了好多年!非常感谢,朋友。
【解决方案2】:

有一种方法可以以CMake 的方式抑制来自第三方标头的警告。

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

系统关键字很可能是您想要的。

If SYSTEM is specified, the compiler will be told 
the directories are meant as system include directories on some platforms

SYSTEM 关键字为 GCC/Clang 添加了 -isystem。而不是将目录视为普通的包含目录。

# GCC docs
Warnings from system headers are normally suppressed.
On the assumption that they usually do not indicate real problems
and would only make the compiler output harder to read.

有一段时间,直到最近在 CMake 3.22 中才有 MSVC 的解决方案,因为 MSVC 编译器终于添加了对此的支持。

这是MSVC blog post,他们在此讨论新的编译器功能。

The “Ninja” and “NMake Makefiles” generators now use
the MSVC “-external:I” flag for system includes. 
This became available as of VS 16.10 
(toolchain version 14.29.30037).

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 2010-12-24
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 2017-01-24
    • 1970-01-01
    相关资源
    最近更新 更多