I. Introduction
Une fois que la bibliothèque pour le développement est compilée, il est possible de l’utiliser directement depuis le « build tree » pour n’importe quel projet qui en dépend. En général ceci n’est pas une bonne idée si votre équipe de développement est constituée de plusieurs membres, si vous utilisez des systèmes divers et/ou si vous voulez répartir votre travail. C’est ici que la notion d’installation et de version a un sens (1). Le packaging (2) vous permet alors une installation sur un ordinateur différent de celui sur lequel vous avez créé votre projet. Après l’installation de la bibliothèque (ainsi que les entêtes correspondantes et les autres fichiers nécessaires) il serait également agréable de pouvoir l’importer (3) facilement dans un autre projet.
La bonne nouvelle est que CMake gère tout cela avec (encore !) un très petit nombre de lignes de code. En utilisant la commande » install() » vous pouvez choisir quoi installer, où l’installer et, dans une certaine mesure, coupler des fichiers d’extension par composant pour les installateurs interactifs. Vous vous souvenez peut être que je vous ai dit dans un post précédent que CMake est une sorte de trilogie (CMake/CTest/CDash). Eh bien, sachez qu’il existe une suite appelée CPack mais qui n’est pas aussi bien que les premiers (les suites le sont rarement), mais ce dernier a son propre préfixe variable cmake, donc je pense que c’est cool :-). CPack gère la partie mise en paquets qui est générée au-dessus du processus d’installation. Maintenant creusons un peu.
II. Installer les cibles et fichiers localement
Dans notre utilisation de CMake, nous n’avons pas de cible pour chaque bibliothèque ou fichier exécutable. En outre, les tests ne sont pas facilement relocalisable, donc il est préférable de ne pas essayer. Les bibliothèques peuvent être installées dans une arborescence plate, mais les en-têtes doivent se trouver dans une certaine structure de répertoires pour être utilisables, nous devons donc suivre deux stratégies différentes. Finalement, la commande install() a de nombreuses signatures, concentrons-nous donc sur celles qui nous seront utiles.
1. Versionnage
Le versionnage suit la convention CMake (pour être compatible avec les autres outils et commandes) comme expliqué ici :
- #———————————————
- # Versionnage
- set (WEBRTC_MAJOR_VERSION 0) # pas encore complètement testé
- set (WEBRTC_MINOR_VERSION 1) # vraiment pas complètement testé, et pas complètement implémenté non plus
- set (WEBRTC_BUILD_VERSION 1) # devrait être le numéro de révision SVN, mais il est difficile de l’obtenir automatiquement depuis le message de commit de git
- set (WEBRTC_VERSION
- ${WEBRTC_MAJOR_VERSION}.${WEBRTC_MINOR_VERSION}.${WEBRTC_BUILD_VERSION}
- )
- set (WEBRTC_API_VERSION
- # c’est le style ITK/VTK où SOVERSION est constitué de deux nombres…
- « ${WEBRTC_MAJOR_VERSION}.${WEBRTC_MINOR_VERSION} »
- )
- set( WEBRTC_LIBRARY_PROPERTIES ${WEBRTC_LIBRARY_PROPERTIES}
- VERSION « {WEBRTC_VERSION} »
- SOVERSION « ${WEBRTC_API_VERSION} »
- )
Lecture complémentaire:
- The original CMake Versioning file for GIT (très avancé)
2. Configurer les dossiers de destination par type de composant
Ici encore, rien de fantaisiste, nous nous contentons de suivre la convention de CMake de façon à ce que find_package puisse être utilisé ultérieurement (voir la documentation de find_package() sur les chemins attendus).
- #__________________________________________
- # Configurer le « export configuration »
- # WEBRTC_INSTALL_BIN_DIR -binary dir (exécutables)
- # WEBRTC_INSTALL_LIB_DIR -library dir (bibliothèques)
- # WEBRTC_INSTALL_DATA_DIR -share dir (exemples, données, etc.)
- # WEBRTC_INSTALL_INCLUDE_DIR -include dir (en-têtes)
- # WEBRTC_INSTALL_CMAKE_DIR -cmake files (CMake)
- if ( NOT WEBRTC_INSTALL_BIN_DIR )
- set ( WEBRTC_INSTALL_BIN_DIR « bin »)
- endif()
- if ( NOT WEBRTC_INSTALL_LIB_DIR )
- set ( WEBRTC_INSTALL_LIB_DIR « lib » )
- endif()
- if( NOT WEBRTC_INSTALL_DATA_DIR )
- set( WEBRTC_INSTALL_DATA_DIR « share »)
- endif()
- if( NOT WEBRTC_INSTALL_INCLUDE_DIR)
- set( WEBRTC_INSTALL_INCLUDE_DIR « include »)
- endif()
- if( NOT WEBRTC_INSTALL_CMAKE_DIR)
- set( WEBRTC_INSTALL_CMAKE_DIR « lib »)
- endif()
3. Gestion des bibliothèques
Comme nous avons fait pour les tests, nous devrons d’abord importer tous les noms de bibliothèques du système de fichiers avant de pouvoir faire quoi que ce soit. Contrairement aux tests, pour lesquels nous devions gérer différents arguments pour chaque test, toutes les bibliothèques sont traitées de la même façon donc nous pouvons automatiser le processus. La commande file(GLOB_RECURSE) fait exactement cela. Sur Mac, toutes les bibliothèques se trouvent à la racine de l’arborescence de compilation de ninja, mais sous Windows chaque bibliothèque est créée dans son propre sous-répertoire, nous devons donc utiliser le GLOB_RECURSE et pas seulement le GLOB comme pour Mac.
- set(WEBRTC_BUILD_ROOT ${WebRTC_SOURCE_DIR}/src/out/${CMAKE_BUILD_TYPE}) # la variable CMAKE_BUILD_TYPE permet la cohérence avec la cible de compilation
- set(WEBRTC_LIB_EXT a) # valeur par défaut.
- if(WIN32)
- set(WEBRTC_LIB_EXT lib) # vous êtes sous Windows ! donc les noms des bibliothèques ont pour extension .lib 🙂
- endif()
- file( GLOB_recurse # sous Windows, les bibliothèques sont dans des sous-dossiers
- WEBRTC_LIBS # la variable de sortie.
- ${WEBRTC_BUILD_ROOT}/* ${WEBRTC_LIB_EXT} # le motif, c’est-à-dire tous les fichier ayant la bonne extension se trouvant sous la racine du répertoire de compilation
- )
Maintenant, nous pourrions directement alimenter la commande install() avec ceci :
- foreach( lib ${WEBRTC_LIBS}
- install(
- FILES ${lib}
- DESTINATION ${WEBRTC_INSTALL_LIB_DIR}
- COMPONENT Libraries
- )
- endforeach()
Cependant, nous voulons supprimer les bibliothèques qui étaient utilisées pour les tests, et nous devons préparer une liste des bibliothèques pour remplir un fichier de configuration qui sera installé avec les bibliothèques et faciliter l’utilisation de la version installée. La version complète ressemble à cela :
- set(WEBRTC_LIBRARIES » ») # préparation de la configuration pour l’arborescence de complation
- foreach(lib ${WEBRTC_LIBS})
- string(FIND ${lib} « test » IS_TEST)
- if(IS_TEST EQUAL -1)
- get_filename_component(lib_name ${lib} NAME_WE)
- string(REPLACE « lib » « » lib_target_name ${lib_name})
- set(WEBRTC_LIBRARIES ${WEBRTC_LIBRARIES} ${lib_target_name})
- install(
- FILES ${WEBRTC_BUILD_ROOT}/${lib}
- DESTINATION ${WEBRTC_INSTALL_LIB_DIR}
- COMPONENT Libraries
- )
- endif()
- endforeach()
4. Gestion des fichiers d’entête
La partie délicate de la gestion des fichiers d’entête vient du fait que les fichiers qui les incluent supposent que les fichiers d’entête sont rangés selon une certaine arborescence définie à partir d’un répertoire racine spécifique. Les fichiers DEPS donnent quelques indications à propos des répertoires à utiliser pour les directives include :
- # définir les règles pour lesquelles les chemins d’include sont autorisés dans notre source.
- include_rules=[
- # La Base est utilisée uniquement pour construire des tests Android APK et ne doit pas être référencée par le code de production WebRTC
- ‘-base’,
- ‘-chromium’,
- ‘+gflags’,
- ‘+net’,
- ‘+net’,
- ‘+testing’,
- ‘+third_party’,
- ‘+webrtc’,
- ]
À part les flags manquants, ce sont tous les répertoires de niveau supérieur des sources WebRTC. Une rapide vérification (grep -R -h \#include * | sort -u > log) confirme qu’il s’agit bien de la disposition attendue par les directives #include.
Donc pour chacun des répertoires /net, /talk, /testing, /third_party, /webrtc, nous devons parcourir leur arborescence et l’utiliser au moment de l’installation (c’est la principale différence avec le code qui gère les bibliothèques). Ceci justifie l’utilisation de l’option RELATIVE pour la commande file(GLOB_RECURSE).
- file(
- GLOB_RECURSE header_files # variable de sortie
- RELATIVE ${WebRTC_SOURCE_DIR}/src # le chemin sera relatif à /src/, comme attendu par les #includes
- FOLLOW_SYMLINKS # nous devons suivre les liens symboliques vers les sous-dossiers de Chromium
- ${WebRTC_SOURCE_DIR}/src/net/*.h
- ${WebRTC_SOURCE_DIR}/src/talk/*.h
- ${WebRTC_SOURCE_DIR}/src/testing/*.h
- ${WebRTC_SOURCE_DIR}/src/third_party/*.h
- ${WebRTC_SOURCE_DIR}/src/webrtc/*.h
- )
Maintenant il est simple d’écrire la commande d’installation.
- foreach( f ${header_files} )
- get_filename_component( RELATIVE_PATH ${f} PATH ) # NOTE D’ALEX : il semble que les versions récentes de CMake utilisent DIRECTORY à la place de PATH…
- install(
- FILES ${WebRTC_SOURCE_DIR/src/${f}
- DESTINATION ${WEBRTC_INSTALL_INCLUDE_DIR}/${RELATIVE_PATH} # voici la partie délicate
- COMPONENT Headers
- )
- endforeach()
5. Sommes-nous arrivés au bout ?
OUI ! Nous pouvons maintenant installer. Vous avez maintenant une cible d’installation dans votre système de compilation. Sous Mac, vous pouvez simplement taper « make install », sous Windows, si vous utilisez les options par défaut (ninja/MSVC) vous aurez une cible « INSTALL » dans la liste des cibles MSVC. La compilation n’est pas lancée par défaut, vous devez la lancer manuellement. Les droits administrateur sont nécessaires. Par défaut, tout est installé sous /usr/local pour Mac et Unix et sous « Program Files » pour Windows (avec (x86) pour la compilation en 32bits).
Dans un prochain post, je vous montrerais comment assembler ces fichiers dans un package pour les installer sur un ordinateur distant.