我想编写一个cmake文件,在调试和发布版本中为clang ++,g ++和MSVC设置不同的编译器选项。 我目前正在做的事情看起来像这样:
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest /W4")
# Default debug flags are OK
set(CMAKE_CXX_FLAGS_RELEASE "{CMAKE_CXX_FLAGS_RELEASE} /O2")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z -Wall -Wextra -Werror")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} some other flags")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else()
# nothing special for gcc at the moment
endif()
endif()
但我有几个问题:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")
取代append(CMAKE_CXX_FLAGS "Foo")
? CMAKE_CXX_FLAGS
和类似的变量,但我不确定使用其他机制。make foo_debug_clang
。所以我的问题是
我在互联网上找到的大多数参考资料要么过时,要么只显示一些简单的例子。我目前正在使用cmake3.8,但如果这有什么不同,我对更新版本的答案更感兴趣。
答案 0 :(得分:12)
你的方法 - 正如@Tsyvarev评论的那样 - 绝对没问题,因为你已经要求新的"这里的CMake方法是您的代码将转换为:
cmake_minimum_required(VERSION 3.8)
project(HelloWorld)
string(
APPEND _opts
"$<IF:$<CXX_COMPILER_ID:MSVC>,"
"/W4;$<$<CONFIG:RELEASE>:/O2>,"
"-Wall;-Wextra;-Werror;"
"$<$<CONFIG:RELEASE>:-O3>"
"$<$<CXX_COMPILER_ID:Clang>:-stdlib=libc++>"
">"
)
add_compile_options("${_opts}")
add_executable(HelloWorld "main.cpp")
target_compile_features(HelloWorld PUBLIC cxx_lambda_init_captures)
你拿add_compile_options()
和 - 作为@ Al.G。已注释 - &#34;使用脏generator expressions&#34;。
生成器表达式有一些缺点:
$<IF:...,...,...>
表达式仅适用于CMake版本&gt; = 3.8 string(APPEND ...)
,您也可以使用它来优化&#34;您的set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ...
来电。因此,最好使用add_compile_options()
更具可读性和向后兼容性的方法:
if(MSVC)
add_compile_options("/W4" "$<$<CONFIG:RELEASE>:/O2>")
else()
add_compile_options("-Wall" "-Wextra" "-Werror" "$<$<CONFIG:RELEASE>:-O3>")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options("-stdlib=libc++")
else()
# nothing special for gcc at the moment
endif()
endif()
是的,您不再明确指定C ++标准,只需将C++ feature命名为您的代码/目标取决于target_compile_features()
次调用。
对于这个例子,我选择了cxx_lambda_init_captures
,例如较旧的GCC编译器会出现以下错误(例如,如果编译器不支持此功能会发生什么情况):
The compiler feature "cxx_lambda_init_captures" is not known to CXX compiler
"GNU"
version 4.8.4.
您需要编写一个包装器脚本来使用"single configuration" makefile generator构建多个配置,或者使用"multi configuration" IDE作为Visual Studio。
以下是对示例的引用:
所以我使用Open Folder
Visual Studio 2017 CMake支持对以下内容进行了测试,以便在此示例中合并cl,clang和mingw编译器:< / p>
<强> CMakeSettings.json 强>
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x86-Debug",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"buildCommandArgs": "-m -v:minimal",
},
{
"name": "x86-Release",
"generator": "Visual Studio 15 2017",
"configurationType": "Release",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"buildCommandArgs": "-m -v:minimal",
},
{
"name": "Clang-Debug",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "-T\"LLVM-vs2014\"",
"buildCommandArgs": "-m -v:minimal",
},
{
"name": "Clang-Release",
"generator": "Visual Studio 15 2017",
"configurationType": "Release",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "-T\"LLVM-vs2014\"",
"buildCommandArgs": "-m -v:minimal",
},
{
"name": "GNU-Debug",
"generator": "MinGW Makefiles",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"variables": [
{
"name": "CMAKE_MAKE_PROGRAM",
"value": "${projectDir}\\mingw32-make.cmd"
}
]
},
{
"name": "GNU-Release",
"generator": "Unix Makefiles",
"configurationType": "Release",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"variables": [
{
"name": "CMAKE_MAKE_PROGRAM",
"value": "${projectDir}\\mingw32-make.cmd"
}
]
}
]
}
<强>的mingw32-make.cmd 强>
@echo off
mingw32-make.exe %~1 %~2 %~3 %~4
因此,您可以在Visual Studio 2017中使用任何CMake生成器,有一些不健康的引用(2017年9月,可能稍后修复)需要mingw32-make.cmd
中介(删除引号)。
答案 1 :(得分:3)
解决前两点,但不是第三点:
- 我已多次阅读,首先不应手动设置CMAKE_CXX_FLAGS和类似变量,但我不确定使用其他机制。
醇>
您想要的命令是set_property
。 CMake支持一堆属性 - 不是一切,而是很多 - 这样可以省去编译器特定工作的麻烦。例如:
set_property(TARGET foo PROPERTY CXX_STANDARD 17)
对于某些编译器,将导致--std=c++17
,但对于早期的--std=c++1z
(在C ++ 17最终确定之前)。或者:
set_property(TARGET foo APPEND PROPERTY COMPILE_DEFINITIONS HELLO WORLD)
对于gcc,clang和MSVC,会导致-DHELLO
-DWORLD
,但奇怪的编译器可能会使用其他开关。
是否依旧没有像append这样的命令可以让我用
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")
替换append(CMAKE_CXX_FLAGS "Foo")?
set_property
可以在设置模式或附加模式下使用(参见上面的示例)。
我不能说这是否比add_compile_options
或target_compile_features
更合适。
答案 2 :(得分:2)
尤其不是在 CMake 3.19+ 中,其中 presets 是一个选项。在预设中放入警告标志等可选设置,并在 CMakeLists.txt 中仅放入硬构建要求。
继续阅读以了解为什么。
我想编写一个 cmake 文件,在调试和发布版本中为 clang++、g++ 和 MSVC 设置不同的编译器选项。
事情是这样的:您不想编写一个设置不同选项的 CMakeLists.txt,您只想有一个方便的地方来存储您的标志。这就是预设和工具链文件的用武之地(更多内容见下文)。
<块引用>我目前正在做的事情是这样的:
if(MSVC)
# ...
else()
# ...
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# ...
else()
# ...
endif()
endif()
[...] 我已经多次阅读,首先不应该手动设置 CMAKE_CXX_FLAGS 和类似变量,但我不确定要使用什么其他机制。
这是这种结构的问题:
您不想为您的构建维护标志兼容性表。幸运的是,有一个简单的解决方案:不要。
将您想要的标志存储在预设 (CMake 3.19+) 或工具链文件(CMake 3.0+,可能更早)中,并让您的用户选择这些设置如果他们愿意。< /p>
使用预设,就像编写 CMakePresets.json 文件一样简单。有一些extensive examples in the documentation。然后你让你的用户告诉你他们想要使用哪组标志:
# Using presets:
$ cmake --preset=msvc
$ cmake --preset=gcc
$ cmake --preset=clang
# Using toolchains:
$ cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$PWD/cmake/msvc.cmake
$ cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$PWD/cmake/gcc.cmake
$ cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$PWD/cmake/clang.cmake
等等。
<块引用>最重要的是:我在这里这样做的方式,我需要为每个编译器和配置一个单独的构建目录理想情况下,我想将其转换为同一目录中的多个目标,以便我可以例如致电make foo_debug_clang
。
这是一个奇怪的要求,因为无论如何,每个人都必须完全构建所有内容。老实说,我只是建议设置一个包装器 Makefile 来支持此工作流程,因为 (a) CMake 本身不支持它,并且 (b) 扩展 CMake 这样做没有真正的优势。
<块引用>我不知道“接受”,但我绝对发现将硬构建要求与理想构建设置在 CMakeLists.txt 和预设(或工具链文件)分别解决(或回避)了许多此类问题。最终结果是更强大的构建更易于使用。
答案 3 :(得分:1)
另一种方法是使用.rsp文件。
set(rsp_file "${CMAKE_CURRENT_BINARY_DIR}/my.rsp")
configure_file(my.rsp.in ${rsp_file} @ONLY)
target_compile_options(mytarget PUBLIC "@${rsp_file}")
可能会使包含多个和深奥的选项更容易管理。
答案 4 :(得分:1)
您可以使用target_compile_options()来“追加”编译选项。