web-dev-qa-db-fra.com

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

Je demande ceci pour me rappeler la prochaine fois que j'utilise CMake. Cela 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?

127
CivFan

Lorsque vous écrivez des scripts CMake, vous devez en savoir beaucoup sur la syntaxe et sur l’utilisation des variables dans CMake.

La syntaxe

Chaînes utilisant set():

  • set(MyString "Some Text")
  • set(MyStringWithVar "Some other Text: ${MyString}")
  • set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")

Ou avec string():

  • string(APPEND MyStringWithContent " ${MyString}")

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

La portée ou "Quelle est la valeur de ma variable?"

Il y a tout d'abord les "variables normales" et les informations à connaître sur leur portée:

  • Les variables normales sont visibles dans le CMakeLists.txt où elles sont définies et tout est appelé à partir de là (add_subdirectory(), include(), macro() et function()).
  • Les commandes add_subdirectory() et function() sont spéciales, car elles ouvrent leur propre étendue.
    • Signification des variables set(...), elles ne sont visibles que là-bas et elles copient toutes les variables normales du niveau de portée à partir duquel elles sont appelées (appelée portée parent).
    • Donc, si vous êtes dans un sous-répertoire ou une fonction, vous pouvez modifier une variable déjà existante dans la portée parent avec set(... PARENT_SCOPE).
    • Vous pouvez utiliser cet exemple, par exemple. dans les fonctions en passant le nom de la variable en tant que paramètre de fonction. Un exemple serait function(xyz _resultVar) définissant set(${_resultVar} 1 PARENT_SCOPE)
  • D'autre part, tout ce que vous définissez dans les scripts include() ou macro() modifiera les variables directement dans l'étendue de l'endroit d'où elles sont appelées.

Deuxièmement, il y a le "cache de variables globales". Ce que vous devez savoir sur le cache:

  • Si aucune variable normale avec le nom donné n'est définie dans la portée 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 binaire.
  • Les valeurs du cache peuvent être modifiées dans l'application interface graphique de CMake avant d'être générées. Par conséquent, ils ont - par rapport aux variables normales - un type et un docstring. Normalement, je n'utilise pas l'interface graphique, j'utilise donc 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 les entrées de cache existantes que si vous utilisez la syntaxe set(... CACHE ... FORCE). Ce comportement est utilisé, par exemple. par CMake lui-même, car normalement, il ne force pas les entrées de cache 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, juste cmake -D var=value ou avec cmake -C CMakeInitialCache.cmake.
  • Vous pouvez désélectionner 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 conseillerais de réfléchir à l’utilisation des variables de cache (elles sont globales et persistantes). Je préfère normalement la syntaxe set_property(GLOBAL PROPERTY ...) et set_property(GLOBAL APPEND PROPERTY ...) pour définir mes propres variables globales non persistantes.

Pièges de variable et "Comment déboguer les modifications de variable?"

Pour éviter les pièges, vous devez connaître les informations suivantes sur les variables:

  • Les variables locales masquent les variables mises en cache si les deux portent le même nom.
  • Les commandes find_... - si elles aboutissent - écrivent leurs résultats sous forme de variables en cache "afin qu'aucun appel ne recherche à nouveau"
  • Les listes dans CMake sont juste des chaînes avec des délimiteurs de points-virgules et donc les guillemets sont importants
    • set(MyVar a b c) est "a;b;c" et set(MyVar "a b c") est "a b c"
    • Nous vous recommandons de toujours utiliser les 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 la gestion des listes
  • Toute la question de la portée décrite ci-dessus. En particulier, il est recommandé d'utiliser functions() au lieu de macros() car vous ne souhaitez pas que vos variables locales apparaissent dans la portée parent.
  • Un grand nombre de variables utilisées par CMake sont définies avec les appels project() et enable_language(). Il pourrait donc être important de définir certaines variables avant que ces commandes ne soient utilisées.
  • Les variables d'environnement peuvent différer de l'endroit où CMake a généré l'environnement de création et du moment où les fichiers de création sont utilisés.
    • Un changement dans une variable d'environnement ne déclenche pas à nouveau 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 élément mis en cache.

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

  • Utilisez simplement l'ancien style de débogage printf à l'aide de la commande message(). Il existe également des modules prêts à l’emploi fournis avec CMake lui-même: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • Regardez dans le fichier CMakeCache.txt de votre répertoire de sortie binaire. Ce fichier est même généré si la génération actuelle 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'analyse de 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 les 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 "sur place" par l'analyseur)
    • Très pratique par exemple dans les lignes de commande du compilateur/éditeur de liens et dans les environnements à configurations multiples
  • Références
    • Avec ${${...}} vous pouvez donner des noms de variable dans une variable et référencer son contenu.
    • Souvent utilisé pour donner un nom de variable en tant que paramètre de fonction/macro.
  • Constantes (voir if() commande)
    • Avec if(MyVariable), vous pouvez directement vérifier si une variable est vraie/fausse (inutile ici pour le ${...} inclus)
    • Vrai si la constante est 1, ON, YES, TRUE, Y ou un nombre non nul.
    • 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 elle peut prêter à confusion 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. Après que CMake ait substitué les variables, il vérifiera à 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. comme une sorte de modèle set(CMAKE_${lang}_COMPILER ...)
    • Mais soyez conscient cela peut vous donner mal à la tête avec 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 true, car elle est évaluée à if("1" STREQUAL "1")
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") est false, car elle est évaluée à 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 règle CMP0054 . Je recommanderais de toujours définir cmake_policy(SET CMP0054 NEW) sur "n'interprète que les arguments if() comme des variables ou des mots-clés non cités".
  • La option() commande
    • Il s'agit principalement de chaînes mises en cache qui ne peuvent être que ON ou OFF et permettent certaines manipulations spéciales telles que, par exemple. dépendances
    • Mais soyez conscient , ne confondez pas le option avec la commande set. La valeur donnée à option n'est en réalité que la "valeur initiale" (transférée une fois au cache lors de la première étape de configuration) et doit ensuite être modifiée par l'utilisateur via interface graphique de CMake .

Références

225
Florian

Voici quelques exemples de base pour bien démarrer rapidement.

Un élément variable

Définir la variable:

SET(INSTALL_ETC_DIR "etc")

Utiliser la variable:

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

Variable à éléments multiples (liste)

Définir la variable:

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

Utiliser la variable:

add_executable(program "${PROGRAM_SRCS}")

CMake docs sur les variables

13
CivFan

$ENV{FOO} pour une 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.

0
parasrish