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:
- Where does the CMake integration pick up default settings from, and can this be controlled?
- 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.
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.
User changes/adds to Project/CMake Compiler Flags Defaults
The standard way would be to modify the cached compiler flags variables by using tools shipped with CMake like
cmake-gui
andccmake
.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
CMake / Cache / Generate
Or you preset the
CMAKE_CXX_FLAGS
cache variable via aCMakeSettings.json
file:CMake / Change CMake Settings
Force the cache entry with
-DCMAKE_CXX_FLAGS:STRING=...
incmakeCommandArgs
CMakeSettings.json
If you deliver this
CMakeSettings.json
file with your CMake project it gets permanentProject changes to CMake Compiler Flags Defaults
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
CMakeSettings.json
References
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 fileWindows-MSVC.cmake
and language specific settings fromWindows-MSVC-C.cmake
orWindows-MSVC-CXX.cmake
.To inspect the default settings, create a file
CompilerOptions.cmake
in the project directory with the following contents:Then initialize the CMAKE_USER_MAKE_RULES_OVERRIDE variable in your
CMakeLists.txt
: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:
So the warning setting
/W3
is picked up from the CMake variableCMAKE_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 theCompilerOptions.cmake
by adding the following lines to the file:The warning flags can then be controlled by setting the target compile options in
CMakeLists.txt
: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 inOpen Folder
mode, choose the commandCache ... -> Delete Cache Folders
from theCMake
menu and thenCache ... -> Generate
from theCMake
menu to recreate the build folder.