CMake로 컴파일러의 C ++ 11 지원을 감지하는 방법


78

컴파일러가 C ++ 11을 지원하는지 여부를 CMake가 자동으로 감지하도록하는 방법이 있습니까?

컴파일러가 C ++ 11을 지원하지 않기 때문에 코드가 컴파일되지 않는다는 것을 CMake 실행 중에 사용자에게 알리는 것이 좋습니다. 지금은 C ++ 11 플래그를 설정했습니다. 그러나 컴파일러가이를 지원하지 않는 경우 사용자는 CMake 실행 중에 오류 대신 컴파일 오류를받습니다.

Perfect는 find_package(). 그러나 필요한 기능을 제공하는 모듈이나 기능을 찾지 못했습니다.

또한 컴파일러에 플래그 std=c++0x또는 .NET Framework가 필요한지 감지하는 기능이 있으면 좋을 것 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)

컴파일러 옵션 add_definitions을 설정 CMAKE_CXX_FLAGS하는 대신 명령을 사용하는 이유는 무엇 입니까?
Li Dong

답변:


104

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 ++ 기능을 지정하고 C ++ 표준을 유도하여 C ++ 파일을 컴파일해야하는 C ++ 표준을 CMake에 알리는 두 가지 방법이 있습니다. CMake는 C ++ 컴파일러가 올바른 명령 줄 플래그 (예 : -std = c ++ 11)로 호출되는지 확인합니다.

1. 명시 적으로 C ++ 표준 지정

CMake 대상에 대해 CMake 속성 CXX_STANDARDCXX_STANDARD_REQUIRED 를 설정하여 C ++ 표준을 명시 적으로 지정할 수 있습니다.

$ 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_constexpr , cxx_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})

12
이 작업을 대상별로 수행해야하는 것은 약간 고통 스럽습니다. "어디서나 C ++ 11을 사용하라"고 말하고이를 수행하는 것이 편리 할 것입니다.
Marc Glisse 2015-06-10

5
속성 범위에서 CXX_STANDARD 11작동하지 않는 것처럼 보입니다 GLOBAL.
abergmeier

9
@MarcGlisse의 @abergmeier은 당신이 할 수있는, 현재 CMake의 범위를 정의하려면set(CMAKE_CXX_STANDARD 11)
typ1232

6
이 방법 -std=gnu++11은 비표준 확장을 추가 하고 활성화 하기 때문에 여전히 몇 가지 문제가 있습니다. 나는 std=c++11이러한 비표준 확장, 이식성 중 하나를 먼저 사용하려고 할 때만 정말로 좋아 하고 오류가 발생합니다.
user1942027 2011 년

8
@RaphaelMiedl 나는이 질문을하고 대답을 얻었다. 링크를 참조 하십시오 . 기본적으로 SET (CMAKE_CXX_EXTENSIONS OFF)를 사용합니다.
doc07b5

42

이 시점에서 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 ()

답변 한 지 6 개월이 지났습니다. 업데이트 된 내용이 있습니까? 이 문제가 아직 해결되지 않은 것 같습니다.
Jack Poulson 2013 년

2
불행히도 나는 여전히 더 나은 해결책을 알지 못합니다. CMake 메일 링리스트에이 문제를 제기하는 것이 도움이 될 수 있습니다.
mavam

4
하이 잭과 마티아스,이 의견은 매우 늦게 알고 있지만, 일부 C ++ 11 지원이 마침내 CMake에 추가 된 것 같습니다 : public.kitware.com/Bug/view.php?id=13842 나의 이해는이 것입니다 11 월 초에 출시 될 예정인 CMake 3.1의 일부입니다.
ryan

1
멋지군요. 일단 이것이 주류가되면 대답을 업데이트하겠습니다. 이제 .NET을 통해 C ++ 버전을 CMake 대상과 연결할 수있는 것 같습니다 set_property(TARGET tgt PROPERTY CXX_STANDARD 11).
mavam

@LucasB, 사실이지만 Eric은 이미 훨씬 더 좋은 답변을 제공합니다.
mavam

9

이 글을 쓰는 시점 (GCC 4.8 이전) 에서는 C ++ 11 플래그를 감지하여 추가하는 것이 좋지 않을 수 있습니다. 이는 표준 (적어도 GCC의 경우)을 변경하면 ABI 호환성이 깨져 링크 오류가 발생할 수 있기 때문입니다.

따라서 C ++ 11 표준의 사용을 명시 적으로 동안 컴파일러 설정으로 지정해야 프로젝트의 초기 CMake 구성 , 예를 들어,

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

즉, -std = c ++ 11 사용은 별도의 컴파일러처럼 취급해야하며 프로젝트에서 혼합하거나 변경해서는 안됩니다.


이제 우리는 GCC 4.8 이후에 상황이 동일합니까?
Jack Poulson 2013

본질적으로 그렇습니다. 아니면 컴파일러 정의가 추가 될 필요가있다, GCC 5 등 자세한 내용은 여기에 있습니다 : developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi
매트 맥코믹

8

사용하다:

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) 활성화 에서 가져온 것 입니다.


2
여보세요! 불행히도 솔루션은 C ++ 표준 버전 설정을 위해 지정된 플래그를 지원하는 컴파일러에서만 작동합니다. C ++ 11을 지원하지만 해당 플래그를 지원하지 않는 컴파일러의 경우 솔루션은 거짓 부정을 제공합니다. 예를 들어 MS VS 2015는 통과하지 못합니다.
Innokentiy Alaytsev

6

CMake 3.8 이상을 사용하는 경우 C ++ 11 이상cxx_std_11 을 요청 하는 기능을 사용할 수 있습니다 .

target_compile_features(Hello PUBLIC cxx_std_11)

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에서 작동하는지 확인했습니다. 3.1 문서는 작동해야하므로이 문서 않습니다.


1

여기에서 찾을 수있는 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()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.