How to set warning level in CMake?

CmakeWarning Level

Cmake Problem Overview


How to set the warning level for a project (not the whole solution) using CMake? Should work on Visual Studio and GCC.

I found various options but most seem either not to work or are not consistent with the documentation.

Cmake Solutions


Solution 1 - Cmake

In modern CMake, the following works well:

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

My colleague suggested an alternative version:

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

Replace ${TARGET_NAME} with the actual target name. -Werror is optional, it turns all warnings into errors.

Or use add_compile_options(...) if you want to apply it to all targets as suggested by @aldo in the comments.

Also, be sure to understand the difference between PRIVATE and PUBLIC (public options will be inherited by targets that depend on the given target).

Solution 2 - Cmake

UPDATE: This answer predates the Modern CMake era. Every sane CMake user should refrain from fiddling with CMAKE_CXX_FLAGS directly and call the target_compile_options command instead. Check the mrts' answer which presents the recommended best practice.

You can do something similar to this:

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

Solution 3 - Cmake

Some CMake modules I've written include experimental 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}"
)

Result for Xcode:

  • Set CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION Xcode attribute (aka build settings -> warnings -> suspicious implicit conversions -> YES)
  • Add compiler flag: -Werror

Makefile gcc and clang:

  • Add compiler flags: -Wconversion, -Werror

Visual studio:

  • Add compiler flags: /WX, /w14244

Solution 4 - Cmake

As per Cmake 3.23.1 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 and Clang share these flags, so this should cover all 3.

Solution 5 - Cmake

Here is the best solution I found so far (including a compiler check):

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

The GCC equivalent is -Wall (untested).

Solution 6 - Cmake

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

If you use target_compile_options - cmake will try to use double /W* flag, which will give warning by compiler.

Solution 7 - Cmake

> How to set the warning level for a project (not the whole solution) using CMake?

(I assume this to mean a CMake target, and not a CMake project.)

> I found various options but most seem either not to work or are not consistent with the documentation.

Kitware's APIs may be trying to deter you from making your build system brittle and error-prone. The special-casing encouraged by other answers to this question violate at least two important principles of modern CMake build systems...

Firstly, prefer not to specify toolchain-specific details in CMakeLists.txt files. It makes the build system brittle. For example, if a new warning appears in a future version of the toolchain, the compiler will emit an error and your user may need to hack your project in order to build the target.

Instead, write toolchain-agnostic CMakeLists.txt files and preserve the user's ability to customise as they see fit. Ideally, your project should build everywhere with vanilla toolchain configuration - even if that doesn't enable your preferred warnings by default.

Secondly, if you intend to link binaries together, flags should be consistent. This reduces the risk of incompatibility which could result in an ill-formed program. However, warning flags are unlikely to affect code generation, so it may be safe to vary these between the targets you link together.

So... if you wish to specify flags per toolchain and if you absolutely must have different flags for different targets, use custom variables:

# CMakeLists.txt
project(my_project)

add_executable(my_target source_file.cpp)
target_compile_options(my_target PRIVATE "${MY_PROJECT_ELEVATED_WARNING_FLAGS}")

There are many ways to set these variables, such as CMakeCache.txt, a toolchain file, and via CMAKE_PROJECT_INCLUDE_BEFORE. But the simplest way is on the command line during configuration, for GCC

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

for MSVC

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWernightView Question on Stackoverflow
Solution 1 - CmakemrtsView Answer on Stackoverflow
Solution 2 - CmakemloskotView Answer on Stackoverflow
Solution 3 - Cmakeuser2288008View Answer on Stackoverflow
Solution 4 - CmakeJayView Answer on Stackoverflow
Solution 5 - CmakeWernightView Answer on Stackoverflow
Solution 6 - CmakeTarmoPikaroView Answer on Stackoverflow
Solution 7 - CmakeJohn McFarlaneView Answer on Stackoverflow