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

IIn*_*ble 21 cmake visual-c++ visual-studio-2017

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

# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(foo)
add_executable(foo foo.cpp)
Run Code Online (Sandbox Code Playgroud)

// foo.cpp
int main() {}
Run Code Online (Sandbox Code Playgroud)

这正确地生成了构建脚本,并且编译和链接没有任何问题.那很简单.

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

明显的解决方案

add_compile_options("/W4")
Run Code Online (Sandbox Code Playgroud)

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

cl : Command line warning D9025: overriding '/W3' with '/W4'
Run Code Online (Sandbox Code Playgroud)

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

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()
Run Code Online (Sandbox Code Playgroud)

然而,这有两个问题:

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

我的问题是双重的:

  1. CMake集成从哪里获取默认设置,是否可以控制?
  2. 如何设置编译器选项?(如果这个主题过于宽泛,我会很乐意帮助您设置警告级别.)


1 顺便说一下,我复制的解决方案没有考虑到/Wall选项,这也是不兼容的/W4.

sak*_*kra 25

编译器的默认设置是从位于ModulesCMake安装目录中的标准模块文件中获取的.使用的实际模块文件取决于平台和编译器.例如,为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()
Run Code Online (Sandbox Code Playgroud)

然后在您的:中初始化CMAKE_USER_MAKE_RULES_OVERRIDE变量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)
Run Code Online (Sandbox Code Playgroud)

在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
 ...
Run Code Online (Sandbox Code Playgroud)

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

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

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()
Run Code Online (Sandbox Code Playgroud)

然后可以通过在以下位置设置目标编译选项来控制警告标志CompilerOptions.cmake:

...
add_executable(foo foo.cpp)
target_compile_options(foo PRIVATE "/W4")
Run Code Online (Sandbox Code Playgroud)

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

在对CMAKE_CXX_FLAGS文件进行更改时,必须重新创建构建文件夹.在CompilerOptions.cmake模式下使用Visual Studio 2017时,Open FolderCache ... -> Delete Cache Folders菜单中选择命令,然后CMakeCache ... -> Generate菜单中重新创建构建文件夹.

  • 关于默认值来自何处的完美解释,并且在单个位置调整默认值看起来也是一个可维护的解决方案。用于转储变量及其值列表的脚本也非常有用。由于我之前找不到任何这些,我将假设存在我不知道的资源。您知道有什么可以推荐的学习 CMake 的资源(在线或书籍)吗? (2认同)

Flo*_*ian 5

把我的评论变成答案

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

现在,要更改CMake生成的编译器设置时需要区别的是以下用例:

  1. 附加的编译器标志CMake未定义与更改CMake的预设设置
  2. 项目默认设置与项目用户定义的设置

因此,让我们讨论这些情况的常见解决方案。


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

标准方法是使用CMake附带的工具(如cmake-gui和)来修改缓存的编译器标志变量ccmake

要在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
    
    Run Code Online (Sandbox Code Playgroud)
  • CMake / Cache / Generate


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

  • CMake / Change CMake Settings

    -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"
            }
        ]
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果您CMakeSettings.json随CMake项目一起提供此文件,它将永久保存


项目更改为CMake编译器标志默认值

如果您想保留大多数CMake的编译器标志,@ sakra的答案肯定是正确的方法。

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

从上面的示例中可以看到:

VS2017工具链.cmake

set(CMAKE_CXX_FLAGS "/DWIN32 /D_WINDOWS /Wall /GR /EHsc" CACHE INTERNAL "")
Run Code Online (Sandbox Code Playgroud)

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"
            }
        ]
    }
Run Code Online (Sandbox Code Playgroud)

参考文献


squ*_*les 5

在 CMake 3.15 中,CMake 引入了针对此 MSVC 特定警告的修复:

cl : Command line warning D9025: overriding '/W3' with '/W4'
Run Code Online (Sandbox Code Playgroud)

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

在 CMake 3.14 及更低版本中使用类似 MSVC 的编译器时,默认情况下/W3会添加类似警告标志CMAKE_<LANG>_FLAGS。对于想要以编程方式选择不同警告级别的项目来说,这是有问题的。特别是,它需要CMAKE_<LANG>_FLAGS在了解 CMake 内置默认值的情况下对变量进行字符串编辑,以便可以替换它们。

CMAKE_<LANG>_FLAGSCMake 3.15 及更高版本倾向于在默认值中省略警告标志。

除了此修复之外,CMake 还引入了策略CMP0092,该策略允许您在必要时切换回该OLD行为(默认添加警告标志)。