web-dev-qa-db-ja.com

CMakeでコンパイラのC ++ 11サポートを検出する方法

コンパイラがC++ 11をサポートしているかどうかをCMakeが自動的に検出する方法はありますか?

コンパイラがC++ 11をサポートしていないため、CMakeの実行中にコードがコンパイルされないことをユーザーに通知するのは良いことです。現時点では、C++ 11フラグを設定しています。ただし、コンパイラがサポートしていない場合、CMakeの実行中にエラーではなくコンパイルエラーが発生します。

完璧はfind_package()のように機能するものです。ただし、必要な機能を提供するモジュールまたは機能は見つかりませんでした。

さらに、コンパイラがstd=c++0xフラグまたはstd=c++11フラグを必要とするかどうかを検出する機能があると便利です。

利用可能なものはありますか、自分でこれを開発する必要がありますか?

以下はこれまでに使用したコードの一部ですが、GNU'c GCCコンパイラーでのみ機能します。もっと一般的な解決策があればいいですね。

if(CMAKE_COMPILER_IS_GNUCXX)
   execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
   if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)
        message(STATUS "C++11 activated.")
        add_definitions("-std=gnu++11")
   elseif(GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3)
        message(WARNING "C++0x activated. If you get any errors update to a compiler which fully supports C++11")
        add_definitions("-std=gnu++0x")
   else ()
        message(FATAL_ERROR "C++11 needed. Therefore a gcc compiler with a version higher than 4.3 is needed.")   
   endif()
else(CMAKE_COMPILER_IS_GNUCXX)
   add_definitions("-std=c++0x") 
endif(CMAKE_COMPILER_IS_GNUCXX)
70
tune2fs

CMakeバージョン3.1.0以降を使用している場合、C++コンパイラがサポートするC++機能を検出できます。

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(foobar CXX)
message("Your C++ compiler supports these C++ features:")
foreach(i ${CMAKE_CXX_COMPILE_FEATURES})
  message("${i}")
endforeach()

ただし、通常、CMakeスクリプトでCMake変数CMAKE_CXX_COMPILE_FEATURESを使用する必要はありません。代わりに、C++標準を明示的に指定するか、必要なC++機能を指定してCMakeにC++標準を誘導させることにより、C++ファイルをコンパイルするC++標準をCMakeに伝える方法が2つあります。 CMakeは、正しいコマンドラインフラグ(-std = c ++ 11など)でC++コンパイラが呼び出されることを確認します。

1. C++標準を明示的に指定する

CMakeプロパティを設定することで、C++標準を明示的に指定できます CXX_STANDARD および CXX_STANDARD_REQUIRED CMakeターゲットの場合。

$ cat /tmp/src/CMakeLists.txt
project(foobar CXX)
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
add_executable(prog main.cc)
set_property(TARGET prog PROPERTY CXX_STANDARD 11)
set_property(TARGET prog PROPERTY CXX_STANDARD_REQUIRED ON)
$ cat /tmp/src/main.cc
int main() {
  return 0;
}
$ mkdir /tmp/build
$ cd /tmp/build
$ cmake /tmp/src
-- The CXX compiler identification is GNU 4.8.2
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/build
$ make VERBOSE=1 | grep main.cc | grep -- "-c"
/usr/bin/c++    -std=gnu++11 -o CMakeFiles/prog.dir/main.cc.o -c /tmp/src/main.cc
$

2.必要なC++機能を指定し、CMakeにC++標準を誘導させる

CMakeコマンド target_compile_features を使用して、CMakeターゲットで使用されるC++機能を指定できます。このリストからCMakeは、使用されるC++標準を誘導します。 CMakeグローバルプロパティ CMAKE_CXX_KNOWN_FEATURES は、選択可能なC++機能をリストします。

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
message("Your CMake version supports these C++ features:")
get_property(known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
foreach(i ${known_features})
  message("${i}")
endforeach()

たとえば、次のファイル名main.ccのC++プログラムは、C++ 11の機能を利用します:cxx_strong_enums cxx_constexprcxx_auto_type

#include <cstdlib>

int main(int argc, char *argv[]) {
  enum class Color { Red, Orange, Yellow, Green, Blue, Violet };
  constexpr float a = 3.1415f;
  auto b = a;
  return EXIT_SUCCESS;
}

このCMakeLists.txtファイルはビルドします

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(foobar CXX)
add_executable(foobar main.cc)                                                                                                                                                                                                                                                     
set(needed_features
    cxx_strong_enums
    cxx_constexpr
    cxx_auto_type)
target_compile_features(foobar PRIVATE ${needed_features})
94
Erik Sjölund

この時点で、CMakeにはC++ 11をサポートする便利な形式がありません。理想的には、次のようなC++ 11プロジェクトを指定します。

project(foo CXX11)

CMakeLists.txtの先頭。ただし、CXX11プロジェクトタイプは存在しません(まだ)。それまでは、2段階の手法を使用できます。

  1. コンパイラのタイプとバージョンを決定する
  2. それに応じてビルドフラグを調整します。

たとえば、これは私がClangおよびGCCでC++ 11をサポートするために使用するものです。

# Initialize CXXFLAGS.
set(CMAKE_CXX_FLAGS                "-Wall -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG          "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE        "-O4 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")

# Compiler-specific C++11 activation.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
    execute_process(
        COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
    if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
        message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
    endif ()
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else ()
    message(FATAL_ERROR "Your C++ compiler does not support C++11.")
endif ()
43
mavam

これを書いている時点で (GCC 4.8より前) 、C++ 11フラグを検出して追加するのは得策ではないかもしれません。これは、標準を変更すると(少なくともGCCの場合) ABI互換性が失われる であり、リンクエラーが発生する可能性があるためです。

したがって、C++ 11標準の使用は、 プロジェクトの初期CMake構成 の間にコンパイラー設定で明示的に指定する必要があります。

CXX='g++ -std=c++11' cmake /path/to/source

つまり、-std = c ++ 11の使用は、個別のコンパイラのように扱う必要があり、プロジェクト内で混合したり変更したりしないでください。

9
Matt McCormick

私は このCMakeスクリプト を見つけました。また、個々のC++ 11機能を確認することもできます。ただし、std=C++0xstd=C++11の間で決定できるとは思いません。

9
Mark

つかいます:

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER} has no C++11 support.")
endif()

これは、CMakeでC++ 11(C++ 0x)を有効にするから少し変更したものです。

8
nkout

CMake 3.1 *では、これを行うための適切で簡単な方法は、特定のターゲットにCXX_STANDARDプロパティを使用することです。たとえば、auto(名前はmain.cpp)を使用した次の簡単な例を考えます。

#include <iostream>

int main() {
    auto num = 10;
    std::cout << num << std::endl;
    return 0;
}

次のCMakeLists.txtは、C++ 11サポートを有効にします。

cmake_minimum_required(VERSION 3.3)
project(Hello CXX)

set(SOURCE_FILES main.cpp)
add_executable(Hello ${SOURCE_FILES})

set_property(TARGET Hello PROPERTY
    CXX_STANDARD 11
    CXX_STANDARD_REQUIRED ON
)

これにより、-std=c++11などの必要なフラグが追加されます。 CXX_STANDARD_REQUIREDプロパティは、標準が以前のバージョンに減衰するのを防ぐことに注意してください。


CMAKE_CXX_KNOWN_FEATURESのように、使用するcxx_auto_typeを指定するための、単純ではない適切な方法:

cmake_minimum_required(VERSION 3.3)
project(Hello CXX)

set(SOURCE_FILES main.cpp)
add_executable(Hello ${SOURCE_FILES})
target_compile_features(Hello PRIVATE cxx_auto_type)

* CMake 3.1ではこれを試していませんが、CMake 3.3では動作することを確認しました。 .1のドキュメント はこれをドキュメント化するので、動作するはずです。

4
Levi Morrison

ここで見つけることができるC++ 11サポートを検出および有効化するためのCMakeモジュールを作成しました。
https://github.com/NitroShare/CXX11-CMake-Macros

まだ進行中ですが、Windows/Linux/Macをターゲットとする多くのQtプロジェクトで使用しています。現在、MSVC++、GCC、およびClangのみがサポートされています。

例:

include(CXX11)

check_for_cxx11_compiler(CXX11_COMPILER)

# If a C++11 compiler is available, then set the appropriate flags
if(CXX11_COMPILER)
    enable_cxx11()
endif()
1
Nathan Osman