在跨平台cmake项目中设置编译器标志的现代方法 [英] Modern way to set compiler flags in cross-platform cmake project

查看:81
本文介绍了在跨平台cmake项目中设置编译器标志的现代方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个cmake文件,该文件在调试和发行版本中为clang ++,g ++和MSVC设置不同的编译器选项。
我目前正在做什么:

  if(MSVC)
set(CMAKE_CXX_FLAGS $ {CMAKE_CXX_FLAGS} / std:c ++ latest / W4)
#默认调试标志可以
设置(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}其他标志)$ b $ RASE(CMAKE $ {CMAKE_CXX_FLAGS_RELEASE} -O3)

if( $ {CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
set(CMAKE_CXX_FLAGS $ {CMAKE_CXX_FLAGS} -stdlib = libc ++)
b else()
#目前gcc没什么特别的
endif()
endif()

但是我有几个问题:


  1. 首先,琐碎的事:有没有相对没有命令就像appen一样,它可以让我替换 set(CMAKE_CXX_FLAGS $ {CMAKE_CXX_FLAGS} Foo)加上附加(CMAKE_CXX_FLAGS Foo)

  2. 我已经读过很多遍了,一开始不应该手动设置 CMAKE_CXX_FLAGS 和类似变量,但是我不确定

  3. 最重要的是:在这里,我需要为每个编译器和配置使用单独的构建目录,理想情况下,我希望将其转换为具有多个目标在同一目录中,所以我可以例如呼叫 make foo_debug_clang

所以我的问题是




  • a)有没有更好的方法来编写可以解决我的痛点的cmake脚本?
    解决上述问题的方法?

  • b)是否存在类似的公认的现代最佳实践来建立此类项目?



我在互联网上可以找到的大多数参考文献已经过时或仅显示了一些琐碎的例子。我目前正在使用cmake3.8,但如果有什么不同,我对最新版本的答案更感兴趣。

解决方案

正如@Tsyvarev所评论的那样,您的方法绝对可以,因为自从您在CMake中请求新方法后,这就是您的代码将转换为的内容:

  cmake_minimum_required(版本3.8)

项目(HelloWorld)

字符串(
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)






您采用



CMakeSettings.json

  {
//有关此文件的更多信息,请参见https://go.microsoft.com//fwlink//?linkid=834763。
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:发布,
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:调试,
buildRoot: $ {env.LOCALAPPDATA} \\CMakeBuild\\ $ {workspaceHash} \\build\\ $ {name},
变量:[
{
name: CMAKE_MAKE_PROGRAM,
value: $ {projectDir} \\mingw32 -make.cmd
}
]
},
{
name: GNU-Release,
generator: Unix Makefiles,
configurationType: Release,
buildRoot: $ {env。 LOCALAPPDATA} \\CMakeBuild\\ $ {workspaceHash} \\build\\ $ {name},
变量:[
{
name : CMAKE_MAKE_PROGRAM,
值: $ {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 中介(删除引号)。


I want to write a cmake file that sets different compiler options for clang++, g++ and MSVC in debug and release builds. What I'm doing currently looks something like this:

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

But I have a couple of problems with this:

  1. First the trivial: Is there relly no command like appen that would allow me to replace set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo") with append(CMAKE_CXX_FLAGS "Foo")?
  2. I've read multiple times, that one should not manually set CMAKE_CXX_FLAGS and similar variables in the first place, but im not sure what other mechanism to use.
  3. Most importantly: The way I do it here, I need a separate build directory for each compiler and configuration Ideally I'd like to transform that into havin multiple targets in the same directory so I can e.g. call make foo_debug_clang.

So my questions are

  • a) Is there a better way to write th cmake script that solves my "pain points"? solution to the points mentioned above?
  • b) Is there something like an accepted, modern best practice of how to set up such projects?

Most references I could find on the internet are either out of date or show only trivial examples. I currently using cmake3.8, but if that makes any difference, I'm even more interested in the answer for more recent versions.

解决方案

Your approach would - as @Tsyvarev has commented - be absolutely fine, just since you've asked for the "new" approach in CMake here is what your code would translate to:

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)


You take add_compile_options() and - as @Al.G. has commented - "use the dirty generator expressions".

There are some downsides of generator expressions:

  1. The very helpful $<IF:...,...,...> expression is only available in CMake version >= 3.8
  2. You have to write it in a single line. To avoid it I used the string(APPEND ...), which you can also use to "optimize" your set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ... calls.
  3. It's difficult to read and understand. E.g. the semicolons are needed to make it a list of compile options (otherwise CMake will quote it).

So better use a more readable and backward compatible approach with 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()


And yes, you don't explicitly specify the C++ standard anymore, you just name the C++ feature your code/target does depend on with target_compile_features() calls.

For this example I've chosen cxx_lambda_init_captures which would for e.g. an older GCC compiler give the following error (as an example what happens if a compiler does not support this feature):

The compiler feature "cxx_lambda_init_captures" is not known to CXX compiler

"GNU"

version 4.8.4.


And you need to write a wrapper script to build multiple configurations with a "single configuration" makefile generator or use a "multi configuration" IDE as Visual Studio.

Here are the references to examples:

So I've tested the following with the Open Folder Visual Studio 2017 CMake support to combine in this example the , and compilers:

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

So you can use any CMake generator from within Visual Studio 2017, there is some unhealthy quoting going on (as for September 2017, maybe fixed later) that requires that mingw32-make.cmd intermediator (removing the quotes).

这篇关于在跨平台cmake项目中设置编译器标志的现代方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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