Existe-t-il un moyen de laisser CMake détecter automatiquement si un compilateur prend en charge C++ 11 ou non?
Comme il serait agréable d'informer les utilisateurs lors de l'exécution de CMake que le code ne sera pas compilé car le compilateur ne prend pas en charge C++ 11. Pour le moment, j'ai défini les drapeaux C++ 11. Cependant, si un compilateur ne le prend pas en charge, l'utilisateur obtient des erreurs de compilation au lieu d'une erreur lors de l'exécution de CMake.
Parfait serait quelque chose qui fonctionne comme find_package()
. Cependant, je n'ai trouvé aucun module ou fonction fournissant les fonctionnalités nécessaires.
De plus, il serait bien d'avoir la fonctionnalité pour détecter si le compilateur a besoin des drapeaux std=c++0x
ou std=c++11
.
Y a-t-il quelque chose de disponible ou dois-je le développer moi-même?
Ci-dessous se trouve du code que j'utilise jusqu'à présent, mais il ne fonctionne qu'avec les compilateurs GNU'c GCC. Ce serait bien s'il y avait une solution plus générale.
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)
Si vous avez CMake version 3.1.0 ou ultérieure, vous pouvez détecter les fonctionnalités C++ prises en charge par votre compilateur 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()
Mais normalement, vous n'avez pas besoin d'utiliser la variable CMake CMAKE_CXX_COMPILE_FEATURES dans vos scripts CMake. Au lieu de cela, il existe deux façons de dire à CMake sous quelle norme C++ vos fichiers C++ doivent être compilés, soit en spécifiant explicitement la norme C++ soit en spécifiant les fonctionnalités C++ requises et en laissant CMake induire la norme C++. CMake s'assurera que le compilateur C++ est invoqué avec les indicateurs de ligne de commande corrects (par exemple -std = c ++ 11).
Vous pouvez spécifier explicitement la norme C++, en définissant les propriétés CMake CXX_STANDARD et CXX_STANDARD_REQUIRED pour votre cible 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
$
Vous pouvez utiliser la commande CMake target_compile_features pour spécifier les fonctionnalités C++ qui sont utilisées dans votre cible CMake. À partir de cette liste, CMake induira le standard C++ à utiliser. La propriété globale CMake CMAKE_CXX_images._FEATURES répertorie les fonctionnalités C++ parmi lesquelles vous pouvez choisir.
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()
Par exemple, ce programme C++ avec le nom de fichier main.cc utilise les fonctionnalités de 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;
}
Ce fichier CMakeLists.txt le construirait
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})
À ce stade, CMake n'a pas de formulaire pratique pour prendre en charge C++ 11. Idéalement, vous devez spécifier un projet C++ 11 comme ceci:
project(foo CXX11)
au début de votre CMakeLists.txt
. Mais le CXX11
le type de projet n'existe pas (encore). Jusque-là, vous pouvez utiliser une technique en deux étapes:
Par exemple, voici ce que j'utilise pour prendre en charge C++ 11 avec Clang et GCC:
# 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 ()
Au moment d'écrire ces lignes (pré-GCC 4.8) , ce n'est peut-être pas une bonne idée de détecter les drapeaux C++ 11 et de les ajouter. En effet, la modification de la norme (au moins pour GCC) rompt la compatibilité ABI , ce qui peut entraîner des erreurs de liaison.
Par conséquent, l'utilisation de la norme C++ 11 doit être explicitement spécifiée avec le paramètre du compilateur lors de la configuration CMake initiale du projet , par ex.
CXX='g++ -std=c++11' cmake /path/to/source
Autrement dit, l'utilisation de -std = c ++ 11 doit être traitée comme un compilateur distinct, qui ne doit pas être mélangé ou modifié dans un projet.
J'ai trouvé ce script CMake qui prétend faire exactement ce dont vous avez besoin. Il peut également vérifier les fonctionnalités individuelles de C++ 11. Je ne pense pas qu'il puisse décider entre std=C++0x
et std=C++11
bien que.
Utilisation:
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()
Cela vient de Activation de C++ 11 (C++ 0x) dans CMake avec des modifications mineures.
Dans CMake 3.1 *, la manière simple et appropriée de procéder consiste à utiliser le CXX_STANDARD
propriété pour une cible donnée. Par exemple, étant donné cet exemple simple utilisant auto
(nommé main.cpp
):
#include <iostream>
int main() {
auto num = 10;
std::cout << num << std::endl;
return 0;
}
Le suivant CMakeLists.txt
activera la prise en charge de 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
)
Cela ajoutera tous les indicateurs nécessaires tels que -std=c++11
. Notez que le CXX_STANDARD_REQUIRED
la propriété empêchera la norme de se décomposer en une version antérieure.
La manière appropriée et pas aussi simple de spécifier le CMAKE_CXX_KNOWN_FEATURES
que vous utilisez, comme 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)
* Je n'ai pas essayé ceci sur CMake 3.1, mais j'ai vérifié que cela fonctionne dans CMake 3.3. Le documentation pour 3.1 documente cela donc cela devrait fonctionner.
Nous avons écrit un module CMake pour détecter et activer le support C++ 11 que vous pouvez trouver ici:
https://github.com/NitroShare/CXX11-CMake-Macros
C'est toujours un travail en cours, mais nous l'utilisons pour un certain nombre de projets Qt qui ciblent Windows/Linux/Mac. Actuellement, seuls MSVC++, GCC et Clang sont pris en charge.
Exemple:
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()