Skip to content

It is impossible to reliably use target_compile_options() on MSVC.

Description of the problem

Please, consider the following CMakeLists.txt:

cmake_minimum_required (VERSION 3.14)
project(Foo VERSION 0.1.0 LANGUAGES CXX)

add_executable(foo)
target_sources(foo PRIVATE Foo.cpp)

if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    target_compile_options(foo PRIVATE -Wall
                                       -Wextra
                                       -Wpedantic
                                       -Werror)
    target_compile_options(foo PRIVATE -fno-exceptions
                                       -fno-rtti)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    target_compile_options(foo PRIVATE /W4
                                       /WX)
    target_compile_options(foo PRIVATE /EHs-c-
                                       /GR-)
endif()

The problem is that building this project on Windows via MSVC, using Ninja or NMake, yields the following warnings:

cl : Command line warning D9025 : overriding '/W3'  with '/W4'
cl : Command line warning D9025 : overriding '/EHs' with '/EHs-'
cl : Command line warning D9025 : overriding '/EHc' with '/EHc-'
cl : Command line warning D9025 : overriding '/GR'  with '/GR-'

Origin of the problem

The reason why these warnings are reported by MSVC is because compiler options of the foo target
are conflicting with default compiler options provided by CMake:

CMAKE_CXX_FLAGS                = /DWIN32 /D_WINDOWS /W3 /GR /EHsc
CMAKE_CXX_FLAGS_DEBUG          = /MDd /Zi /Ob0 /Od /RTC1
CMAKE_CXX_FLAGS_RELEASE        = /MD /O2 /Ob2 /DNDEBUG
CMAKE_CXX_FLAGS_MINSIZEREL     = /MD /O1 /Ob1 /DNDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO = /MD /Zi /O2 /Ob1 /DNDEBUG

Note that, these flags are set here: //CMake/Modules/Platform/Windows-MSVC.cmake

Interestingly, the situation is little bit different on Visual Studio,
since conflicting options will be replaced, except for options controlling C++ exception handling:

cl /c /Zi /W4 /WX /Od /Ob0 /D WIN32 /D _WINDOWS /EHsc /RTC1 /MDd /GS /GR- /EHs-c- Foo.cpp

Scale of the problem

This is nothing new - this problem is known for a very long time and affects almost all CMake developers.
These are just few selected links showing the widespread it is:

Lack of proper solution

The only "solution" to this problem, that I've managed to find, is to change CMake global state:

  • by either filtering out conflicting compiler options from CMAKE_CXX_FLAGS:
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  • or by overriding CMake default compiler flags via CMAKE_USER_MAKE_RULES_OVERRIDE:
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/MyOverride.cmake")

# MyOverride.cmake
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT}")

Note that, these approaches are recommended by the official CMake FAQ:

The problem is none of these approaches allow for removal conflicting flags from a single CMake target.
This makes setting compiler options using Modern CMake style almost impossible!
Fiddling with global CMake state breaks ability to locally reason about the build system and
prevents cleanly composing CMake targets into large projects.

Direction to move forward

If there is no way of solving this issue locally, within single CMake target,
what kind of approach fixing this situation would you guys suggest?

Sure, there is a proposal, which would allow developers to manage compiler warnings portably in CMake:

However, mentioned proposal doesn't solve this issue completely,
because controlling these compiler options would still be a problem:

  • C++ exceptions (/EHsc vs /EHs-c-)
  • RTTI (/GR /GR-)
  • Run-Time Library (/MD[d] vs /MT[d] vs /LD[d])

Unfortunately I don't know ideal solution of this problem:

  • introducing in CMake portable way of disabling C++ exceptions and RTTI is very tricky,
    because different compilers handle this differently: Portable way to disable RTTI and exceptions
  • changing how CMake handles compiler options would not be backward compatible
  • disabling MSVC command-line warning D9025 is undesirable and even not possible

Do you guys have any suggestions how to solve this problem?

Best regards, Mateusz

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information