如何在 CMake 中设置警告级别?

如何使用 CMake项目(不是整个解决方案)设置 警告级别? 应该在 视觉工作室海湾合作委员会上工作。

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

135075 次浏览

下面是我目前为止找到的最好的解决方案(包括编译器检查) :

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

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

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

你可以做类似的事情:

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()

一些 制作我写的模块包括实验性的 交叉平板报警抑制:

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_CONVERSION Xcode 属性 (又名 构建设置-> 警告-> 可疑的隐式转换-> 是的)
  • 添加编译器标志: -Werror

生成文件 gcc 和 clang:

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

视觉工作室:

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

连结

在现代 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 在评论中建议的那样将其应用于所有目标,请使用 add_compile_options(...)

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

正如@davidfong 在注释中指出的,自 CMake v3.24以来,有一个 CMAKE_COMPILE_WARNING_AS_ERROR变量将编译警告视为错误。如果它设置在 CMakeLists.txt内,用户仍然可以使用 --compile-no-warning-as-error cmake标志关闭它。如果您想手动添加警告为错误,请将 Windows 中的 /WX和其他地方的 -Werror添加到 target_compile_options

if(MSVC)
string(REGEX REPLACE "/W[1-3]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()

如果您使用 target_compile_options-cmake 将尝试使用双 /W*标志,这将提供编译器的警告。

根据 Cmake 3.24.2文档:

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()

海湾合作委员会和 Clang 共享这些标志,因此这应该涵盖所有3个。

如何使用 CMake 设置项目(而非整个解决方案)的警告级别?

(我假设这是指 A CMake < em > target ,而不是 A CMake < em > project 。)

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

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

首先,希望 没有在 CMakeLists.txt 文件中指定特定于工具链的详细信息。它使构建系统变得脆弱。例如,如果新的警告出现在工具链的未来版本中,编译器将发出一个错误,您的用户可能需要修改您的项目以生成目标。

相反,编写与工具链无关的 CMakeLists.txt 文件,并保留用户根据需要进行定制的能力。理想情况下,您的项目应该使用普通的工具链配置到处构建——即使默认情况下不启用首选警告。

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

因此,如果您希望为每个工具链指定标志,并且如果您绝对必须为不同的目标使用不同的标志,那么可以使用自定义变量:

# 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、 工具链文件和通过 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>