【发布时间】:2011-01-23 01:15:44
【问题描述】:
如何使用CMake为项目(不是整个解决方案)设置警告级别?应该在 Visual Studio 和 GCC 上工作。
我找到了各种选项,但大多数似乎要么不起作用,要么与文档不一致。
【问题讨论】:
标签: cmake warning-level
如何使用CMake为项目(不是整个解决方案)设置警告级别?应该在 Visual Studio 和 GCC 上工作。
我找到了各种选项,但大多数似乎要么不起作用,要么与文档不一致。
【问题讨论】:
标签: cmake warning-level
在现代 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(...)。
另外,请务必了解PRIVATE 和PUBLIC 之间的区别(公共选项将由依赖于给定目标的目标继承)。
【讨论】:
add_compile_options(...)。
else() 或 endif() 中的条件。
add_compile_options() 的问题是警告将传播到通过add_subdirectory() 添加的目标。如果您以这种方式包含外部库,如果该库被设计为具有不同的警告级别,您可能会收到大量警告。
更新:这个答案早于现代 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()
【讨论】:
/Wall 标志(名为 EnableAllWarnings)。它产生的警告比/W4 还要多。但是根据我的经验,它会产生太多警告。
/Wall 可以用于如果您想遵循警告的“减法”策略,就像 clang 的 -Weverything。您无需选择要启用的警告,而是启用所有内容,然后选择要禁用的特定警告。
一些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
【讨论】:
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 个。
【讨论】:
add_compile_options 是目录范围的,而 target_compile_options 仅适用于单个目标。
这是迄今为止我找到的最佳解决方案(包括编译器检查):
if(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
add_definitions(/W2)
endif()
GCC 等价物是 -Wall(未经测试)。
【讨论】:
-Wall 并且可能是 -Wextra,详见 gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
-W -Wall -Wextra -pedantic。 -Wextra IIRC 在更高版本的 GCC 中替换了 -W,但出于兼容性考虑,我将两者都保留了。
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 没有解决这个基本选项(设置警告级别)的事实令人难以置信。
如何使用 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>
【讨论】: