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:
CMAKE_CXX_FLAGS
, applying to all C++ targets. This may not be intended (not an issue for me right now).My question is two-fold:
/Wall
option, that is incompatible with /W4
as well.
CMake does check for the compiler ids by compiling special C/C++ files. So no need to manually include from Module/Compiler or Module/Platform . This will be automatically done by CMake based on its compiler and platform checks.
In Visual Studio You can set compiler options for each project in its Visual Studio Property Pages dialog box. In the left pane, select Configuration Properties, C/C++ and then choose the compiler option category.
About CMake. CMake is an extensible, open-source system that manages the build process in an operating system and in a compiler-independent manner.
Getting started with CMake in Visual Studio. To start, create a simple CMakeLists.txt file in the same folder with your cpp file as in the example below. Then, open the folder in Visual Studio (via File > Open > Folder… or devenv.exe <foldername>). Alternatively, open a folder inside VS containing one of your existing CMake projects.
In Visual Studio 2019, the CMake Settings Editor provides a convenient way to edit your settings. For more information, see Customize CMake settings. One setting, intelliSenseMode isn't passed to CMake, but is used only by Visual Studio. Use the CMakeLists.txt file in each project folder just as you would in any CMake project.
CMake does come with some compiler switches preset. For visual studio those are mainly standard link libraries, warning levels, optimization levels, exception handling, debug information and platform specific defines. What you now have to differentiate when you want to change a CMake generated compiler settings are the following use cases:
The C++ CMake tools for Windows component uses the Open Folder feature to consume CMake project files (such as CMakeLists.txt) directly for the purposes of IntelliSense and browsing. Both Ninja and Visual Studio generators are supported.
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 using Open Folder
in Visual Studio 2017, the following information will be shown 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 a rules 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.
Turning my comment into an answer
CMake does come with some compiler switches preset. For visual studio those are mainly standard link libraries, warning levels, optimization levels, exception handling, debug information and platform specific defines.
What you now have to differentiate when you want to change a CMake generated compiler settings are the following use cases:
So let's discuss common solutions for those cases.
The standard way would be to modify the cached compiler flags variables by using tools shipped with CMake like cmake-gui
and ccmake
.
To achieve this in Visual Studio you would have to:
CMake / Cache / View CMakeCache
Manually change e.g. CMAKE_CXX_FLAGS
to /Wall
CMakeCache.txt
//Flags used by the compiler during all build types.
CMAKE_CXX_FLAGS:STRING= /DWIN32 /D_WINDOWS /Wall /GR /EHsc
CMake / Cache / Generate
Or you preset the CMAKE_CXX_FLAGS
cache variable via a CMakeSettings.json
file:
CMake / Change CMake Settings
Force the cache entry with -DCMAKE_CXX_FLAGS:STRING=...
in cmakeCommandArgs
CMakeSettings.json
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x86-Debug (all warnings)",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "-DCMAKE_CXX_FLAGS:STRING=\"/DWIN32 /D_WINDOWS /Wall /GR /EHsc\"",
"buildCommandArgs": "-m -v:minimal"
}
]
}
If you deliver this CMakeSettings.json
file with your CMake project it gets permanent
If you want to keep most of CMake's compiler flags in place, @sakra's answer is definitely the way to go.
For my VS projects I've put the CXX flag settings into a toolchain file coming with the project itself. Mainly to freeze those settings and don't have a dependency the CMake version used or any environment variables set.
Taking the example from above that would look like:
VS2017Toolchain.cmake
set(CMAKE_CXX_FLAGS "/DWIN32 /D_WINDOWS /Wall /GR /EHsc" CACHE INTERNAL "")
CMakeSettings.json
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x86-Debug (all warnings)",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=\"${projectDir}\\VS2017Toolchain.cmake\"",
"buildCommandArgs": "-m -v:minimal"
}
]
}
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 toCMAKE_<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 theCMAKE_<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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With