我目前正试图设置一个项目,将使用多个编译器(包括Clang、MSVC和GCC),使用Visual Studio 2019的新CMake功能(特别是使用Clang和Ninja与CMake和VS2019一起使用)。
我正在使用CMake来配置项目,使其“与编译器无关”,因此我不需要编辑代码本身来处理不同的编译器通过预处理指令或#pragma
指令。
此项目需要配置为具有高警告级别(对于MSVC为/W4
,对于Clang为-Wall
、-Wextra
和-Wpedantic
),并且必须将警告视为错误。
当涉及到配置项目的MSVC部分时,我没有任何问题。许多这些设置具有“理智”的默认值,可以按照我的期望“正常工作”。然而,当涉及到Clang时,我遇到了一个问题:
我似乎无法禁用第三方库头文件的警告。我目前正在使用Dear Imgui和SFML库。由于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
命令查找我的库源文件(注意:我知道通常不建议使用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)
我尝试过的其他方法:
- 在
set_source_files_properties
CMake函数中放置.h
/.hpp
文件(与.cpp
文件一起)。这对于Dear Imgui有效,但它的所有错误都在.cpp
文件中,而不是在头文件中。对于SFML的头文件无效。 - (对于Dear Imgui而非SFML)将目录包含为
SYSTEM
包含以抑制警告。在Windows上似乎无效。不能使用CMake的find_package
函数做到这一点,因为我正在使用它而不是手动执行所有操作。 - 使用
#pragma
指令。虽然这有效,但每个SFML文件都有数十个不同的错误,我想避免在所有地方使用#pragma
(或将SFML的头文件包装在我的自己的头文件中,只需在其中包装#include
指令即可使用#pragma
)。
在不使用#pragma
的情况下是否可能抑制这些库头文件的警告?我以前从未真正使用过Clang,如果这似乎是一个简单的问题,请谅解,但是在线搜索并没有给我任何有效的结果:
- 在命令行之外(我使用的是带有CMake的Visual Studio)。
- 在Windows上(系统标志似乎无法与此设置一起使用)。
- 可以与CMake特定的操作一起使用。
target_include_directories(<target> SYSTEM <dir>)
来指定这个选项。 - OlivSYSTEM
关键字,因为我不是自己包含其目录,而是使用find_package
命令以其自己的方式包含了SFML目录。 - micka190target_include_directories
函数中(使用SYSTEM
关键字),但似乎不起作用。我还尝试在find_package
和target_link_libraries
函数之前和之后放置该函数,但仍然无效。这可能是因为警告/错误是头文件本身引起的? - micka190-isystem
的实验性等效项(请参见https://devblogs.microsoft.com/cppblog/broken-warnings-theory/),因此`clang-cl`并没有明确支持它。你仍然可以通过`-Xclang -isystem /path/to/libs/imgui`进行黑客攻击。但是...它似乎存在缺陷,可能会导致导入的头文件无法编译...你必须自己检查。(我将尝试将其转换为带有一些代码示例的答案,但我需要查看我正在处理的代码)。 - R2RT