如何在 Visual Studio 2017 中使用 CMake 设置编译器选项 [英] How to set compiler options with CMake in Visual Studio 2017

查看:234
本文介绍了如何在 Visual Studio 2017 中使用 CMake 设置编译器选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Visual Studio 2017 带有完整的 CMake 集成.为了了解这种组合,我从这个基本示例开始:

# CMakeLists.txtcmake_minimum_required(版本 3.8)项目(富)add_executable(foo foo.cpp)

//foo.cppint main() {}

这会正确生成构建脚本,并且可以毫无问题地编译和链接.这很容易.

另一方面,尝试设置编译器选项却并非易事.就我而言,我试图将警告级别设置为 4.

显而易见的解决方案

add_compile_options("/W4")

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

<块引用>

cl : 命令行警告 D9025: 用 '/W4' 覆盖 '/W3'

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

if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")字符串(正则表达式替换/W[0-4]"/W4"CMAKE_CXX_FLAGS${CMAKE_CXX_FLAGS}")别的()设置(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}/W4")万一()

然而,这有两个问题:

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

我的问题有两个:

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


1 顺便说一句,我复制的解决方案未能考虑 /Wall 选项,该选项也与 /W4 不兼容.

解决方案

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

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

# 记录所有 *_INIT 变量get_cmake_property(_varNames 变量)列表(REMOVE_DUPLICATES _varNames)列表(排序_varNames)foreach (_varName ${_varNames})if (_varName MATCHES "_INIT$")消息(状态${_varName}=${${_varName}}")万一()endforeach()

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

# CMakeLists.txtcmake_minimum_required(版本 3.8)设置(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_LIST_DIR}/CompilerOptions.cmake")项目(富)add_executable(foo foo.cpp)

在 Visual Studio 2017 中使用 Open Folder 打开目录后配置项目时,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 项目或目标级别的警告级别,可以通过在文件中添加以下行来更改 CompilerOptions.cmake 中的 CMAKE_CXX_FLAGS_INIT 变量:

if (MSVC)# 从 CMAKE_CXX_FLAGS_INIT 中删除默认警告级别字符串(正则表达式替换/W[0-4]"CMAKE_CXX_FLAGS_INIT${CMAKE_CXX_FLAGS_INIT}")万一()

然后可以通过在 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 ... ->从 CMake 菜单中删除缓存文件夹,然后 Cache ... ->从 CMake 菜单生成 以重新创建构建文件夹.

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

这篇关于如何在 Visual Studio 2017 中使用 CMake 设置编译器选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆