How to set compiler options with CMake in Visual Studio 2017

visual studio cmake
cmake visual studio compiler flags
cmake visual studio 2017
cmake could not find any instance of visual studio
how to pass compiler options to cmake
cmake visual studio 2019 command line
cmake visual studio 2017 command line
cmake set msvc compiler

Visual Studio 2017 comes with full CMake integration. To learn about this combination, I was starting with this basic sample:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(foo)
add_executable(foo foo.cpp)

and

// foo.cpp
int main() {}

This properly generates build scripts, and compiles and links with no issues. That was easy.

Trying to set compiler options, on the other hand, turned out to be anything but trivial. In my case I was attempting to set the warning level to 4.

The obvious solution

add_compile_options("/W4")

didn't pan out as expected. The command line passed to the compiler now contains both /W4 (as intended) as well as /W3 (picked up from somewhere else), producing the following warning:

cl : Command line warning D9025: overriding '/W3' with '/W4'

To work around this, I would need to replace any incompatible compiler option(s) instead of just adding one. CMake does not provide any immediate support for this, and the standard solution (as this Q&A suggests) seems to be:

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

This, however, has two issues:

  • It sets the global CMAKE_CXX_FLAGS, applying to all C++ targets. This may not be intended (not an issue for me right now).
  • It doesn't scale. For every compiler option to add, you would have to read up on incompatible options, and manually strip those first. This will inevitably fail1.

My question is two-fold:

  1. Where does the CMake integration pick up default settings from, and can this be controlled?
  2. How do you set compiler options in general? (If this is too broad a topic, I'd be happy for help on setting the warning level only.)


1 Incidentally, the solution I replicated fails to account for the /Wall option, that is incompatible with /W4 as well.

The default settings for the compiler are picked up from standard module files located in the Modules directory of the CMake installation. The actual module file used depends on both the platform and the compiler. E.g., for Visual Studio 2017, CMake will load the default settings from the file Windows-MSVC.cmake and language specific settings from Windows-MSVC-C.cmake or Windows-MSVC-CXX.cmake.

To inspect the default settings, create a file CompilerOptions.cmake in the project directory with the following contents:

# log all *_INIT variables
get_cmake_property(_varNames VARIABLES)
list (REMOVE_DUPLICATES _varNames)
list (SORT _varNames)
foreach (_varName ${_varNames})
    if (_varName MATCHES "_INIT$")
        message(STATUS "${_varName}=${${_varName}}")
    endif()
endforeach()

Then initialize the CMAKE_USER_MAKE_RULES_OVERRIDE variable in your CMakeLists.txt:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
set (CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/CompilerOptions.cmake")
project(foo)
add_executable(foo foo.cpp)

When the project is configured upon opening the directory in Visual Studio 2017, the following information will be show in the IDE's output window:

 ...
 -- CMAKE_CXX_FLAGS_DEBUG_INIT= /MDd /Zi /Ob0 /Od /RTC1
 -- CMAKE_CXX_FLAGS_INIT= /DWIN32 /D_WINDOWS /W3 /GR /EHsc
 -- CMAKE_CXX_FLAGS_MINSIZEREL_INIT= /MD /O1 /Ob1 /DNDEBUG
 -- CMAKE_CXX_FLAGS_RELEASE_INIT= /MD /O2 /Ob2 /DNDEBUG
 -- CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT= /MD /Zi /O2 /Ob1 /DNDEBUG
 ...

So the warning setting /W3 is picked up from the CMake variable CMAKE_CXX_FLAGS_INIT which then applies to all CMake targets generated in the project.

To control the warning level on the CMake project or target level, one can alter the CMAKE_CXX_FLAGS_INIT variable in the CompilerOptions.cmake by adding the following lines to the file:

if (MSVC)
    # remove default warning level from CMAKE_CXX_FLAGS_INIT
    string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT}")
endif()

The warning flags can then be controlled by setting the target compile options in CMakeLists.txt:

...
add_executable(foo foo.cpp)
target_compile_options(foo PRIVATE "/W4")

For most CMake projects it makes sense to control the default compiler options in an override file instead of manually tweaking variables like CMAKE_CXX_FLAGS.

When making changes to the CompilerOptions.cmake file, it is necessary to recreate the build folder. When using Visual Studio 2017 in Open Folder mode, choose the command Cache ... -> Delete Cache Folders from the CMake menu and then Cache ... -> Generate from the CMake menu to recreate the build folder.

Customize CMake build settings in Visual Studio, Visual Studio 2017 introduces built-in support for handling CMake can specify additional command line arguments to be passed to the build� The first time you select a configuration, Visual Studio creates a CMakeSettings.json file in your project's root folder. This file is used to re-create the CMake cache file, for example after a Clean operation. To add an additional configuration, right click CMakeSettings.json and choose Add Configuration.

CMake projects in Visual Studio, My final CMakeLists.txt has some unholy mess of variable setting and clearing at multiple points to try and fix this, but nothing seems to work. All executable CMake targets are shown in the Startup Item dropdown in the General toolbar. Select one to start a debugging session and launch the debugger. You can also start a debug session from Solution Explorer. First, switch to CMake Targets View in the Solution Explorer window. Then, right-click on an executable and select Debug. This command automatically starts debugging the selected target based on your active configuration.

In CMake 3.15, CMake introduced a fix for this MSVC-specific warning:

cl : Command line warning D9025: overriding '/W3' with '/W4'

and the compiler warning flags (like /W3) are no longer automatically added. So by upgrading to CMake 3.15 or greater, this warning should no longer appear. From the docs:

When using MSVC-like compilers in CMake 3.14 and below, warning flags like /W3 are added to CMAKE_<LANG>_FLAGS by default. This is problematic for projects that want to choose a different warning level programmatically. In particular, it requires string editing of the CMAKE_<LANG>_FLAGS variables with knowledge of the CMake builtin defaults so they can be replaced.

CMake 3.15 and above prefer to leave out warning flags from the value of CMAKE_<LANG>_FLAGS by default.

Along with this fix, CMake introduced policy CMP0092, which allows you to switch back to the OLD behavior (adding the warning flags by default) if necessary.

CMake support in Visual Studio, Interestingly, the situation is little bit different on Visual Studio, This makes setting compiler options using Modern CMake style almost impossible! Using VS2017, it does appear to update the /O flags correctly in the project settings EXCEPT� Note: Ensure you have Visual Studio 2017 installed (CMake comes embedded within Visual Studio). Setting Up In order to get started, we first need to create a empty directory (this can anywhere, I generally like to put all my C++ projects in the root C:\ location like C:\CppDev so in this case it would be C:\CppDev\VsCmakeExample ).

Some Visual Studio 2017 compiler and linker flags are , Visual Studio 2017 comes with full CMake integration. To learn about this combination, I was starting with this basic sample: # CMakeLists.txt� Right click on any file in the Solution Explorer and select “Compile” or build the file open in the editor via the main CMake menu: CMake Cache Generation Settings. Visual Studio automatically configures and generates the cache for your CMake projects by default when you open them for the first time.

(#19084) � Issues � CMake / CMake, Visual Studio 2017 comes with its own distribution of CMake. Build variables, cache and environment variables can all be set with the same CMAKE_CXX_FLAGS used for specifying flags for the VC++ compiler. The v141 toolset that comes with Visual Studio 15 2017 is selected by default. The CMAKE_GENERATOR_TOOLSET option may be set, perhaps via the cmake(1) -T option, to specify another toolset. For each toolset that comes with this version of Visual Studio, there are variants that are themselves compiled for 32-bit (x86) and 64-bit (x64) hosts

How to set compiler options with CMake in Visual Studio 2017 , with CMake you can have several build types. the most important generator ( like Visual Studio or XCode) you specify this in the build step, build type, what it means, flags (AppleClang, GCC), flags (MSVC 2017)� I simply could NOT open the properties window for the project. I just upgraded my Visual Studio to . Microsoft Visual Studio Community 2017 Version 15.9.19 Microsoft .NET Framework Version 4.7.02558 Visual C++ 2017 00369-60000-00001-AA098. on Windows 7 Ultimate SP1 6.1.7601. Anyways, properties simply wouldn't do anything, no error, no window

Comments
  • Some compiler options can be changed by cross-platform-compatible CMake variables or properties. But warning levels unfortunately don't have those generic way of defining them. You may want to take a look at the work of @ruslo found here and the discussion about extending CMake itself here.
  • @Florian: Thanks for the confirmation, that CMake does not directly support setting the warning level. Still, the links you posted are not immediately helpful to me: Ruslo's work only supports setting /Wall, while the second link works by tweaking CMAKE_CXX_FLAGS. The answer posted by @sakra to override the default compiler options looks like a cleaner solution, allowing more fine-grained control over setting compiler options.
  • When I was working on an answer for this question I noticed that add_compile_options() command does replace/overwrites the warning level specification instead of just appending it to "Additional Options" like when you append to CMAKE_CXX_FLAGS. I'm not sure why there is a difference (have to check in CMake's code), but can please give add_compile_options("/W4") a try? In my CMake version 3.9 I didn't get that compiler warning anymore.
  • @Florian: add_compile_options("/W4") still gives me a compiler warning. I'm using the "Ninja" generator, using the CMake support built into Visual Studio 2017 (15.3.3), so there is no .vcxproj generated along the way (as far as I know). This is using cmake version 3.8.0-MSVC_2.
  • Perfect explanation on where the defaults come from, and adjusting the defaults in a single location also looks like a maintainable solution. The script to dump a list of variables and their values is also very helpful. Since I couldn't find any of this previously, I'm going to assume, that there are resources I don't know of. Do you know of any resources (online or books) to learn CMake you could recommend?
  • Look at the source code ;-) CMake's source contains interesting information in comments, which unluckily isn't available anywhere else, e.g.: github.com/Kitware/CMake/blob/…
  • @sakra That doesn't seem to work in VS2017 15.8. No CMAKE_CXX_FLAGS_ is listed.
  • Those are some nice alternatives. Setting the CMAKE_TOOLCHAIN_FILE variable is particularly appealing, as it pins down the environment to fixed values, allowing those to be put under source control. Still, it feels a bit like an abuse of what toolchain files are meant to be used for. This introduces changes to CMake's behavior (just like the CMAKE_USER_MAKE_RULES_OVERRIDE variable) very early, before CMake builds its first test project. Am I overly concerned, or does this indeed open the potential for issues? (I'm a CMake novice, and my mental model of how CMake works may well be off.)
  • @IInspectable I prefer the toolchain approach also because it separates the different compiler pre-settings very nicely and makes my generic CMakeLists.txt files more readable. And no toolchains are not only for cross-compiling, but you can alternatively use the -C pre-load cache command line option (toolchains just have the advantage that they also propagate into any projects CMake may generate on the fly). And having the flags right from the beginning has the advantage that the compiler checks (configuration step) would fail if I got them wrong.