Quelle est la syntaxe CMake pour définir et utiliser des variables?

Je me demande ceci pour me rappeler la prochaine fois que j’utilise CMake. Il ne colle jamais et les résultats de Google ne sont pas excellents.

Quelle est la syntaxe pour définir et utiliser des variables dans CMake?

Lorsque vous écrivez des scripts CMake, vous avez besoin de beaucoup d’informations sur la syntaxe et l’utilisation des variables dans CMake.

La syntaxe

Chaînes utilisant set() :

  • set(MySsortingng "Some Text")
  • set(MySsortingngWithVar "Some other Text: ${MySsortingng}")
  • set(MySsortingngWithQuot "Some quote: \"${MySsortingngWithVar}\"")

Ou avec une ssortingng() :

  • ssortingng(APPEND MySsortingngWithContent " ${MySsortingng}")

Listes utilisant set() :

  • set(MyList "a" "b" "c")
  • set(MyList ${MyList} "d")

Ou mieux avec list() :

  • list(APPEND MyList "a" "b" "c")
  • list(APPEND MyList "d")

Listes de noms de fichiers:

  • set(MySourcesList "File.name" "File with Space.name")
  • list(APPEND MySourcesList "File.name" "File with Space.name")
  • add_excutable(MyExeTarget ${MySourcesList})

La documentation

  • CMake / Syntaxe de langue
  • CMake: Variables répertorie les chaînes
  • CMake: Variables utiles
  • Commande CMake set()
  • Commande CMake ssortingng()
  • Commande CMake list()
  • Cmake: Expressions de générateur

The Scope ou “Quelle est la valeur de ma variable?”

Il y a tout d’abord les “variables normales” et les choses à savoir sur leur scope:

  • Les variables normales sont visibles par CMakeLists.txt elles sont définies et tout ce qui y est appelé ( add_subdirectory() , include() , macro() et function() ).
  • Les commandes add_subdirectory() et function() sont spéciales car elles ouvrent leur propre scope.
    • Ce qui signifie que les variables set(...) ne sont visibles que là-bas et elles font une copie de toutes les variables normales du niveau de scope à partir duquel elles sont appelées (appelée scope parent).
    • Donc, si vous êtes dans un sous-répertoire ou une fonction, vous pouvez modifier une variable déjà existante dans la scope parent avec set(... PARENT_SCOPE)
    • Vous pouvez utiliser ceci par exemple dans les fonctions en passant le nom de la variable comme paramètre de fonction. Un exemple serait la function(xyz _resultVar) est la valeur set(${_resultVar} 1 PARENT_SCOPE)
  • D’un autre côté, tout ce que vous définissez dans include() scripts include() ou macro() modifiera les variables directement dans la scope d’où elles sont appelées.

Deuxièmement, il y a le “Global Variables Cache”. Ce que vous devez savoir sur le cache:

  • Si aucune variable normale portant le nom indiqué n’est définie dans la scope actuelle, CMake recherchera une entrée de cache correspondante.
  • Les valeurs de cache sont stockées dans le fichier CMakeCache.txt de votre répertoire de sortie binary.
  • Les valeurs dans le cache peuvent être modifiées dans l’ application graphique de CMake avant d’être générées. Par conséquent, par rapport aux variables normales, ils ont un type et un docssortingng . Je n’utilise normalement pas l’interface graphique, donc j’utilise set(... CACHE INTERNAL "") pour définir mes valeurs globales et persistantes.

    Veuillez noter que le type de variable de cache INTERNAL implique FORCE

  • Dans un script CMake, vous ne pouvez modifier que les entrées de cache existantes si vous utilisez la syntaxe set(... CACHE ... FORCE) . Ce comportement est utilisé par exemple par CMake lui-même, car il ne force pas les entrées de cache lui-même et vous pouvez donc le prédéfinir avec une autre valeur.

  • Vous pouvez utiliser la ligne de commande pour définir des entrées dans le cache avec la syntaxe cmake -D var:type=value , simplement cmake -D var=value ou avec cmake -C CMakeInitialCache.cmake .
  • Vous pouvez supprimer des entrées dans le cache avec unset(... CACHE) .

Le cache est global et vous pouvez les définir pratiquement n’importe où dans vos scripts CMake. Mais je vous recommande de réfléchir à deux fois à l’utilisation des variables du cache (elles sont globales et elles sont persistantes). Je préfère normalement la set_property(GLOBAL PROPERTY ...) et set_property(GLOBAL APPEND PROPERTY ...) pour définir mes propres variables globales non persistantes.

Pièges variables et “Comment déboguer les modifications de variables?”

Pour éviter les pièges, vous devez connaître les points suivants concernant les variables:

  • Les variables locales masquent les variables mises en cache si elles portent toutes le même nom
  • Les commandes find_... – en cas de succès – écrivent leurs résultats en tant que variables mises en cache “pour qu’aucun appel ne soit à nouveau recherché”
  • Les listes de CMake ne sont que des chaînes comportant des délimiteurs de points-virgules et, par conséquent, les guillemets sont importants
    • set(MyVar abc) est "a;b;c" et set(MyVar "abc") est "abc"
    • La recommandation est que vous utilisez toujours des guillemets avec la seule exception lorsque vous souhaitez donner une liste sous forme de liste
    • Préfère généralement la commande list() pour gérer les listes
  • Le problème de la scope entière décrit ci-dessus. En particulier, il est recommandé d’utiliser functions() au lieu de macros() car vous ne voulez pas que vos variables locales apparaissent dans la scope parent.
  • Un grand nombre de variables utilisées par CMake sont définies avec les appels project() et enable_language() . Il serait donc important de définir des variables avant que ces commandes ne soient utilisées.
  • Les variables d’environnement peuvent différer de celles où CMake a généré l’environnement make et lorsque les fichiers make sont utilisés.
    • Un changement dans une variable d’environnement ne déclenche pas le processus de génération.
    • En particulier, un environnement IDE généré peut différer de votre ligne de commande. Il est donc recommandé de transférer vos variables d’environnement dans un cache.

Parfois, seules les variables de débogage sont utiles. Ce qui suit peut vous aider:

  • Utilisez simplement l’ancien style de débogage printf en utilisant la commande message() . Il y a aussi des modules prêts à l’emploi livrés avec CMake lui-même: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • Recherchez dans le fichier CMakeCache.txt dans votre répertoire de sortie binary. Ce fichier est même généré si la génération réelle de votre environnement make échoue.
  • Utilisez variable_watch () pour voir où vos variables sont lues / écrites / supprimées.
  • Regardez dans les propriétés du répertoire CACHE_VARIABLES et VARIABLES
  • Appelez cmake --trace ... pour voir le processus complet d’parsing du CMake. C’est en quelque sorte la dernière réserve, car elle génère beaucoup de résultats.

Syntaxe spéciale

  • Variables d’environnement
    • Vous pouvez lire $ENV{...} et écrire des variables d’environnement set(ENV{...} ...)
  • Expressions de générateur
    • Les expressions de générateur $<...> ne sont évaluées que lorsque le générateur de CMake écrit l’environnement de création (comparaison avec les variables normales remplacées “in-place” par l’parsingur)
    • Très pratique, par exemple dans les lignes de commande du compilateur / éditeur de liens et dans les environnements multi-configuration
  • Les références
    • Avec ${${...}} vous pouvez donner des noms de variables dans une variable et référencer son contenu.
    • Souvent utilisé pour donner un nom de variable en tant que paramètre fonction / macro.
  • Valeurs constantes (voir la commande if() )
    • Avec if(MyVariable) vous pouvez directement vérifier une variable pour true / false (pas besoin ici de ${...} )
    • Vrai si la constante est 1 , ON , YES , TRUE , Y ou un nombre différent de zéro.
    • False si la constante est 0 , OFF , NO , FALSE , N , IGNORE , NOTFOUND , la chaîne vide ou se termine par le suffixe -NOTFOUND .
    • Cette syntaxe est souvent utilisée pour quelque chose comme if (MSVC) , mais cela peut être déroutant pour quelqu’un qui ne connaît pas ce raccourci de syntaxe.
  • Substitutions récursives
    • Vous pouvez construire des noms de variables à l’aide de variables. Une fois que CMake a substitué les variables, il vérifie à nouveau si le résultat est une variable elle-même. C’est une fonctionnalité très puissante utilisée dans CMake lui-même, par exemple en tant que sorte de template set(CMAKE_${lang}_COMPILER ...)
    • Mais sachez que cela peut vous donner un casse-tête dans les commandes if () . Voici un exemple où CMAKE_CXX_COMPILER_ID est "MSVC" et MSVC est "1" :
      • if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") est vrai, car il est évalué à if ("1" STREQUAL "1")
      • if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") est faux, car il évalue if ("MSVC" STREQUAL "1")
      • La meilleure solution serait donc – voir ci-dessus – de vérifier directement if (MSVC)
    • La bonne nouvelle est que cela a été corrigé dans CMake 3.1 avec l’introduction de la politique CMP0054 . Je recommande de toujours définir cmake_policy(SET CMP0054 NEW) pour “interpréter uniquement les arguments if() comme des variables ou des mots-clés non classés.”
  • La commande option()
    • Principalement juste des chaînes mises en cache qui peuvent seulement être ON ou OFF et qui permettent certaines manipulations spéciales comme par exemple les dépendances
    • Mais soyez conscient , ne confondez pas l’ option avec la commande set . La valeur donnée à l’ option n’est en réalité que la “valeur initiale” (transférée une fois dans le cache lors de la première étape de configuration) et est ensuite destinée à être modifiée par l’utilisateur via l’interface graphique de CMake .

Les références

  • Comment CMake est-il utilisé?
  • cmake, perdu dans le concept de variables globales (et alternatives à PARENT_SCOPE ou add_subdirectory)
  • En boucle sur une liste de chaînes
  • Comment stocker les parameters de construction CMake
  • CMake comparer à une chaîne vide avec STREQUAL échoué
  • cmake: quand citer des variables?

Voici quelques exemples de base pour commencer rapidement et sale.

Une variable d’article

Définir la variable:

 SET(INSTALL_ETC_DIR "etc") 

Utilisez la variable:

 SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d") 

Variable à éléments multiples (c.-à-d. Liste)

Définir la variable:

 SET(PROGRAM_SRCS program.c program_utils.c a_lib.c b_lib.c config.c ) 

Utilisez la variable:

 add_executable(program "${PROGRAM_SRCS}") 

Documents CMake sur les variables

$ENV{FOO} pour l’utilisation, où FOO est extrait de la variable d’environnement. sinon, utilisez ${FOO} , où FOO est une autre variable. Pour le réglage, SET(FOO "foo") serait utilisé dans cmake.