Je veux écrire un fichier cmake qui définit différentes options de compilation pour clang ++, g ++ et MSVC dans les versions de débogage et de publication. Ce que je fais actuellement ressemble à ceci:
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()
Mais j'ai quelques problèmes avec ceci:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")
par append(CMAKE_CXX_FLAGS "Foo")
?CMAKE_CXX_FLAGS
Et des variables similaires en premier lieu, mais je ne sais pas quel autre mécanisme utiliser.make foo_debug_clang
.Donc mes questions sont
La plupart des références que j'ai pu trouver sur Internet sont obsolètes ou ne montrent que des exemples triviaux. J'utilise actuellement cmake3.8, mais si cela fait une différence, je suis encore plus intéressé par la réponse pour les versions plus récentes.
Votre approche serait - comme l'a commenté @Tsyvarev - tout à fait correcte, tout comme vous avez demandé la "nouvelle" approche dans CMake, voici à quoi votre code se traduirait:
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)
Vous prenez add_compile_options()
et - comme @ Al.G. a commenté - "utilisez le sale expressions du générateur ".
Il existe certains inconvénients des expressions de générateur:
$<IF:...,...,...>
N'est disponible que dans la version CMake> = 3.8string(APPEND ...)
, que vous pouvez également utiliser pour "optimiser" vos appels set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ...
.Il vaut donc mieux utiliser une approche plus lisible et rétrocompatible avec 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()
Et oui, vous ne spécifiez plus explicitement la norme C++, vous nommez juste le fonctionnalité C++ votre code/cible dépend des appels target_compile_features()
.
Pour cet exemple, j'ai choisi cxx_lambda_init_captures
Qui serait par exemple un ancien compilateur GCC donne l'erreur suivante (comme exemple ce qui se passe si un compilateur ne prend pas en charge cette fonctionnalité):
The compiler feature "cxx_lambda_init_captures" is not known to CXX compiler
"GNU"
version 4.8.4.
Et vous devez écrire un script wrapper pour construire plusieurs configurations avec un générateur de makefile "configuration unique" ou utiliser un IDE "multi configuration" comme Visual Studio.
Voici les références d'exemples:
J'ai donc testé ce qui suit avec le support Open Folder
De Visual Studio 2017 CMake pour combiner dans cet exemple les cl , clang et mingw compilateurs:
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
Donc, vous pouvez utiliser n'importe quel générateur CMake à partir de Visual Studio 2017, il y a des citations malsaines en cours (comme pour septembre 2017, peut-être corrigées plus tard) qui nécessitent cet intermédiaire mingw32-make.cmd
(En supprimant les guillemets).
Abordant les deux premiers points, mais pas le troisième:
- J'ai lu plusieurs fois, que l'on ne devrait pas définir manuellement CMAKE_CXX_FLAGS et des variables similaires en premier lieu, mais je ne sais pas quel autre mécanisme utiliser.
La commande que vous souhaitez est set_property
. CMake prend en charge un tas de propriétés - pas tout, mais beaucoup - d'une manière qui vous évite de faire un travail spécifique au compilateur. Par exemple:
set_property(TARGET foo PROPERTY CXX_STANDARD 17)
ce qui pour certains compilateurs entraînera --std=c++17
mais pour les précédents avec --std=c++1z
(avant la finalisation de C++ 17). ou:
set_property(TARGET foo APPEND PROPERTY COMPILE_DEFINITIONS HELLO WORLD)
résultera en -DHELLO
-DWORLD
pour gcc, clang et MSVC, mais pour les compilateurs étranges, il peut utiliser d'autres commutateurs.
Y a-t-il vraiment aucune commande comme append qui me permettrait de remplacer
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} Foo")
parappend(CMAKE_CXX_FLAGS "Foo")?
set_property
Peut être utilisé en mode set ou en mode ajout (voir les exemples ci-dessus).
Je ne peux pas dire si c'est préférable à add_compile_options
Ou target_compile_features
, Cependant.
Vous pouvez utiliser target_compile_options () pour "ajouter" les options de compilation.
Une autre façon consiste à utiliser des fichiers .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}")
ce qui pourrait faciliter l'inclusion d'options multiples et ésotériques.