如何在Visual Studio 2017中使用CMake设置编译器选项

时间:2017-09-01 08:07:45

标签: visual-c++ cmake visual-studio-2017

Visual Studio 2017提供完整的CMake集成。要了解这个组合,我从这个基本样本开始:

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

// foo.cpp
int main() {}

这可以正确生成构建脚本,并且编译和链接没有问题。这很容易。

另一方面,尝试设置编译器选项,结果却是微不足道的。在我的情况下,我试图将警告级别设置为4。

明显的解决方案

add_compile_options("/W4")

没有像预期的那样平息。传递给编译器的命令行现在包含/W4(按预期)和/W3(从其他地方获取),产生以下警告:

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

要解决这个问题,我需要替换任何不兼容的编译器选项,而不是只添加一个。 CMake没有为此提供任何直接支持,标准解决方案(如this Q&A suggests)似乎是:

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

然而,这有两个问题:

  • 设置全局CMAKE_CXX_FLAGS,适用于所有C ++目标。这可能不是故意的(现在对我来说不是问题)。
  • 它没有规模。对于要添加的每个编译器选项,您必须阅读不兼容的选项,并首先手动删除它们。这将不可避免地失败 1

我的问题是双重的:

  1. CMake集成从哪里获取默认设置,是否可以控制?
  2. 如何设置编译器选项? (如果这个主题过于宽泛,我会很乐意帮助您设置警告级别。)
  3. <小时/> 1 顺便提一下,我复制的解决方案无法考虑/Wall选项,这也与/W4不兼容。

3 个答案:

答案 0 :(得分:23)

编译器的默认设置是从位于CMake安装的Modules目录中的标准模块文件中获取的。使用的实际模块文件取决于平台和编译器。例如,对于Visual Studio 2017,CMake将从文件Windows-MSVC.cmake加载默认设置,并从Windows-MSVC-C.cmakeWindows-MSVC-CXX.cmake加载语言特定设置。

要检查默认设置,请在项目目录中创建一个文件CompilerOptions.cmake,其中包含以下内容:

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

然后初始化CMakeLists.txt中的CMAKE_USER_MAKE_RULES_OVERRIDE变量:

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

在Visual Studio 2017中打开目录时配置项目时,IDE的输出窗口中将显示以下信息:

 ...
 -- 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
 ...

因此,警告设置/W3从CMake变量CMAKE_CXX_FLAGS_INIT中获取,然后应用于项目中生成的所有CMake目标。

要控制CMake项目或目标级别的警告级别,可以通过在文件中添加以下行来更改CMAKE_CXX_FLAGS_INIT中的CompilerOptions.cmake变量:

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

然后可以通过在CMakeLists.txt

中设置目标编译选项来控制警告标志
...
add_executable(foo foo.cpp)
target_compile_options(foo PRIVATE "/W4")

对于大多数CMake项目,控制覆盖文件中的默认编译器选项是有意义的,而不是手动调整CMAKE_CXX_FLAGS之类的变量。

更改CompilerOptions.cmake文件时,需要重新创建构建文件夹。在Open Folder模式下使用Visual Studio 2017时,从Cache ... -> Delete Cache Folders菜单中选择命令CMake,然后从Cache ... -> Generate菜单中选择CMake以重新创建构建文件夹。

答案 1 :(得分:5)

将我的评论转化为答案

CMake确实预装了一些编译器开关。对于visual studio,主要是标准链接库,警告级别,优化级别,异常处理,调试信息和特定于平台的定义。

当您想要更改CMake生成的编译器设置时,您现在要区分的是以下用例:

  1. 其他编译器标志CMake未定义与更改CMake的预设设置
  2. 项目默认设置与项目用户定义的设置
  3. 因此,让我们讨论这些案例的常见解决方案。

    用户更改/添加到Project / CMake编译器标志默认值

    标准方法是使用CMake附带的工具(如cmake-guiccmake)修改缓存的编译器标记变量。

    要在Visual Studio中实现此目的,您必须:

    • CMake / Cache / View CMakeCache
    • 手动更改,例如CMAKE_CXX_FLAGS/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

    或者您通过CMAKE_CXX_FLAGS文件预设CMakeSettings.json缓存变量:

    • CMake / Change CMake Settings

      -DCMAKE_CXX_FLAGS:STRING=...

      中强制使用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"
              }
          ]
      }
      
    • 如果您将此CMakeSettings.json文件与CMake项目一起提供,则会永久

    项目更改为CMake Compiler Flags Defaults

    如果你想保留大部分CMake的编译器标志,@ sakra的回答肯定是要走的路。

    对于我的VS项目,我已将CXX标志设置放入项目本身附带的工具链文件中。主要是冻结这些设置,并且不使用CMake版本或任何环境变量设置依赖。

    以上面的例子为例:

    <强> 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"
                }
            ]
        }
    

    参考

答案 2 :(得分:0)

在CMake 3.15中,CMake针对此MSVC特定警告引入了fix

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

和编译器警告标志(如/W3)不再自动添加。因此,通过升级到CMake 3.15或更高版本,此警告将不再出现。从文档中:

  

在CMake 3.14及更低版本中使用类似MSVC的编译器时,默认情况下,将/W3之类的警告标志添加到CMAKE_<LANG>_FLAGS中。对于希望以编程方式选择其他警告级别的项目而言,这是个问题。特别是,它需要使用CMake内置默认值的知识来对CMAKE_<LANG>_FLAGS变量进行字符串编辑,以便可以替换它们。

     

CMake 3.15及更高版本更喜欢默认情况下从CMAKE_<LANG>_FLAGS的值中删除警告标志。

与此修复程序一起,CMake引入了策略CMP0092,该策略可让您在必要时切换回OLD行为(默认情况下添加警告标志)。