Installation
(Cette partie ne traite bien sûr pas de l'installation de CMake lui-même, mais de l'installation d'un code que vous compilez avec CMake.)
L'idée d'installation
Installation : après la compilation, copie des exécutables ou des bibliothèques compilées vers une autre arborescence, avec d'autres exécutables ou bibliothèques venant de projets indépendants. Nous avons donc 3 arborescences pour un projet : source, compilation et installation. Intérêts de l'installation :
- Regrouper pour mieux trouver. Le répertoire d'installation des
exécutables peut faire partie de la variable PATH. Les bibliothèques
et les
.mod
sont aussi cherchés dans un endroit conventionnel, sans avoir besoin de connaître les divers répertoires de compilation. -
Avoir une version "stable" installée et continuer à développer et compiler ailleurs la version en développement.
-
Ne garder que le nécessaire. Possibilité de détruire après installation les répertoires source et de compilation. Les fichiers installés sont en général beaucoup moins nombreux que ceux du répertoire de compilation (fichiers objets, fichiers générés par CMake etc.).
Chemins d'installation conventionnels
/usr/local
pour les installations communes à tous les utilisateurs (si on a l'autorisation).~/.local
pour soi-même seulement, est un choix assez courant.
D'autres choix sont possibles.
Le chemin à choisir ci-dessus est la racine d'une arborescence. En dessous, on trouve les répertoires :
bin
pour les exécutableslib
pour les bibliothèquesinclude
pour les fichiers inclus (surtout en C ou C++) et les fichiers.mod
man
, fichiers lus par la commandeman
libexec
pour les exécutables non destinés à être appelés directement
Installation d'un exécutable
Ajouter dans CMakeLists.txt
la commande :
install(TARGETS plouf)
pour installer la cible plouf. À la configuration, choisir la racine
de l'arborescence d'installation avec la variable de cache prédéfinie
CMAKE_INSTALL_PREFIX
. L'exécutable sera installé dans le
sous-répertoire bin sous cette racine. Ni le répertoire désigné par
CMAKE_INSTALL_PREFIX
ni ses sous-répertoires (bin, etc.) n'ont
besoin d'exister à l'avance.
Pour installer :
make install
Manipulation 27
Ajouter dans le projet Coriolis une commande d'installation. Tester.
Installation d'une bibliothèque : install(TARGETS)
install(TARGETS ma_bibli EXPORT ${PROJECT_NAME}Targets INCLUDES DESTINATION include)
déclare :
- que la cible
ma_bibli
indiquée doit être installée lors de la commandemake install
-
que la cible fait partie d'un ensemble de cibles à installer appelé
${PROJECT_NAME}Targets
(on pourrait choisir ici un nom arbitraire) -
que le sous-répertoire
include
deCMAKE_INSTALL_PREFIX
doit être ajouté à la propriétéINTERFACE_INCLUDE_DIRECTORIES
de la cible installée.
Installation d'une bibliothèque : le fichier .mod
install(FILES ${PROJECT_BINARY_DIR}/ma_bibli.mod TYPE INCLUDE)
déclare que le fichier ma_bibli.mod
doit être installé, que ce
fichier est de type INCLUDE
et doit donc aller dans le répertoire
correspondant de CMAKE_INSTALL_PREFIX
.
Installation d'une bibliothèque : le fichier config, sans dépendances
install(EXPORT ${PROJECT_NAME}Targets DESTINATION lib/cmake/${PROJECT_NAME} NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}Config.cmake)
demande la création, lors de make install
, d'un fichier
${PROJECT_NAME}Config.cmake
, dans le répertoire
lib/cmake/${PROJECT_NAME}
sous CMAKE_INSTALL_PREFIX
. Ce fichier
est destiné à find_package
et permet de générer les cibles avec
toutes leurs propriétés d'interface. Les cibles concernées sont celles
qui font partie de ${PROJECT_NAME}Targets
(ensemble de cibles défini
par l'option EXPORT de install(TARGETS)
). Les cibles générées auront
le préfixe spécifié après l'option NAMESPACE.
Installation d'une bibliothèque : le fichier config, avec dépendances
install(EXPORT ${PROJECT_NAME}Targets DESTINATION lib/cmake/${PROJECT_NAME} NAMESPACE ${PROJECT_NAME}::)
La seule différence avec le cas sans dépendances est l'absence de
l'option FILE. Le nom du fichier est alors le nom par défaut :
${PROJECT_NAME}Targets.cmake
. Ce fichier sera créé, lors de make
install
, dans le répertoire lib/cmake/${PROJECT_NAME}
sous
CMAKE_INSTALL_PREFIX
. Il sera inclus dans
${PROJECT_NAME}Config.cmake
.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake DESTINATION lib/cmake/${PROJECT_NAME})
Rappel : le fichier ${PROJECT_NAME}Config.cmake
a été créé par
configure_file
.
Utilisation d'une bibliothèque dans le répertoire de compilation
Même si la bibliothèque est installée, on peut vouloir utiliser la
bibliothèque dans son répertoire de compilation (par exemple pour
utiliser la bibliothèque compilée en mode DEBUG, alors que celle
installée est compilée en mode RELEASE, ou pour tester une version en
développement). Nous avons vu que l'utilisation dans le répertoire de
compilation était possible grâce à la commande export(TARGETS)
.
Si on a ajouté dans CMakeLists.txt
des commandes d'installation, il
est plus cohérent de remplacer export(TARGETS)
par export(EXPORT)
.
export(EXPORT)
Cas sans dépendances, remplacer :
export(TARGETS target NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}Config.cmake)
par :
export(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}Config.cmake)
Cas avec dépendances, remplacer :
export(TARGETS target NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}Targets.cmake)
par :
export(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::)
(sans option FILE)
${PROJECT_NAME}Targets
a été défini par l'option EXPORT de
install(TARGETS)
.
La commande export(EXPORT)
a pour effet, comme export(TARGETS)
, de
créer ${PROJECT_NAME}Config.cmake
(cas sans dépendances) ou
${PROJECT_NAME}Targets.cmake
(cas avec dépendances) dans le
répertoire de compilation.
Installation d'une bibliothèque : BUILD_INTERFACE
La commande :
target_include_directories(nr_util INTERFACE ${PROJECT_BINARY_DIR})
qui permet l'utilisation de la bibliothèque englobée, ou non
installée, n'est plus possible si des commandes d'installation sont
présentes. On ne peut ajouter ${PROJECT_BINARY_DIR}
à l'interface
de la cible installée : c'est un chemin absolu dans le répertoire de
compilation. Solution :
target_include_directories(nr_util INTERFACE $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>)
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
vaut
${PROJECT_BINARY_DIR}
pour les commandes de compilation et rien pour
les commandes d'installation.
Manipulation 28
- Ajouter les commandes d'installation aux bibliothèques
NR_util
, Jumble etNumer_Rec_95
. Installer les bibliothèques. - Tester l'utilisation des bibliothèques installées avec le programme Coriolis.
Module regroupeur d'une bibliothèque
Une bibliothèque peut proposer un module unique d'interface avec l'utilisateur, qui ne fait que regrouper les interfaces des modules de la bibliothèque :
module ma_bibli
use foo_m
use bar_m
use plouf_m
end module ma_bibli
Dans le programme utilisateur de la bibliothèque, le seul module utilisé est le regroupeur :
use ma_bibli, only: foo
Lors de la compilation de la bibliothèque, des fichiers .mod
vont
être créés pour les modules contenant les procédures et pour le module
regroupeur.
Fichiers .mod
d'une bibliothèque nécessaires au programme utilisateur
- Quels fichiers
.mod
sont nécessaires à la compilation du programme utilisateur ? Seulement le.mod
regroupeur,ma_bibli.mod
, ou tous les.mod
de la bibliothèque ? - La réponse dépend du compilateur (et de sa version). Avec gfortran 9
et ifort 15, le fichier
.mod
regroupeur contient toute l'information, lui seul est utile. Avec ifort 19, nagfor 6 et pgfortran 2016, tous les.mod
doivent être présents.
Conséquences pour le CMakeLists.txt
de la bibliothèque
-
Le fait que la compilation du programme utilisateur d'une bibliothèque puisse nécessiter l'accès à tous les
.mod
de la bibliothèque n'apporte pas de nouvelle contrainte si la bibliothèque est utilisée dans son répertoire de compilation : la propriétéINTERFACE_INCLUDE_DIRECTORIES
de la bibliothèque, qui permet de trouver le module regroupeur, permet aussi de trouver dans le même répertoire les autres.mod
. -
Par contre, c'est une nouvelle contrainte si la bibliothèque est utilisée dans son répertoire d'installation : tous les
.mod
doivent avoir été installés, pas seulement le.mod
regroupeur.
Installation de tous les .mod
d'une bibliothèque
Créer tous les .mod
dans un répertoire séparé :
set_target_properties(target PROPERTIES Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/modules)
Ajouter ce répertoire à la propriété INCLUDE_DIRECTORIES
de la
bibliothèque dans le répertoire de compilation :
target_include_directories(target PUBLIC $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/modules>)
au lieu de :
target_include_directories(target INTERFACE $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>)
Installer le répertoire dans un sous-répertoire de include
(plutôt
que de mettre en vrac dans include
tous les .mod
de toutes les
bibliothèques) :
install(DIRECTORY ${PROJECT_BINARY_DIR}/modules/DESTINATION include/${PROJECT_NAME})
au lieu de :
install(FILES ${PROJECT_BINARY_DIR}/ma_bibli.mod TYPE INCLUDE)
Nota bene : le /
après modules
dans la commande
install(DIRECTORY)
ci-dessus, pour copier le contenu du répertoire
et non le répertoire lui-même.
Indiquer que include/${PROJECT_NAME}
est dans la propriété
INTERFACE_INCLUDE_DIRECTORIES
de la cible installée :
install(TARGETS target EXPORT ${PROJECT_NAME}Targets INCLUDES DESTINATION include/${PROJECT_NAME})
au lieu de :
install(TARGETS target EXPORT ${PROJECT_NAME}Targets INCLUDES DESTINATION include)
Possibilité d'ajouter dans CMakeLists.txt
un test pour décider selon
le compilateur si on installe seulement le .mod
regroupeur ou tous
les .mod
.
Manipulation 29
Modifier les CMakeLists.txt
des bibliothèques pour que
l'installation et l'utilisation des bibliothèques installées avec les
compilateurs NAG, Intel récent ou PGI soient possibles.