Récemment, nous avons eu plusieurs clients qui ont décidé de compiler notre librairie C++ sous Linux. Cet procédure est documentée dans le fichier README et il y a un article qui explique comment compiler la libraire avec l'IDE Code::Blocks. Toutefois, nous n'avions pas encore documenté comment utiliser CMake pour compiler la librairie et l'utiliser dans un programme. Cette semaine, nous nous attaquons donc à ce sujet.
Note: nous partons du principe que vous avez déjà un minimum de connaissances du langage C++ et de notre librairie de programmation. Si ce n'est pas de cas, nous vous conseillons de commencer par la lecture de notre article "Comment débuter en C++ avec les modules Yoctopuce" qui explique comment fonctionne notre librairie.
Tout d'abord, quelques mots sur CMake. CMake n'est ni un compilateur ni un IDE, mais un "système de construction logicielle". En d'autres termes, le rôle de CMake n'est pas de construire directement l’exécutable mais de préparer une liste de commandes à effectuer pour générer l’exécutable. Sous Linux en général, on utilise CMake pour générer un fichier GNU make qui va ensuite utiliser gcc ou g++ pour compiler le fichier source et créer l’exécutable.
CMake génère les makefiles qui permettent de compiler l'application à l'aide de gcc
Un projet CMake est composé de fichiers source et d'un ou plusieurs fichiers CMakeLists.txt qui contiennent les informations nécessaires pour compiler l'application, comme l'emplacement de fichiers source, le nom de l'exécutable, les librairies à utiliser, etc...
On pourrait se poser la question "Pourquoi ne pas utiliser directement GNU make?". En effet, GNU make permet déjà de décrire les commandes à exécuter pour transformer un fichier .cpp en exécutable, mais sa syntaxe est très compliquée, et devient presque incompréhensible pour les gros projets. Comme nous allons le voir plus bas, la syntaxe de CMake est bien plus simple, et simplifie grandement la vie du développeur.
En plus, CMake est open source et est disponible sur presque toutes le plateformes.
Pour ces raisons, depuis la version 1.10.42060 de notre librairie C++, nous avons ajouté un fichier CMakeLists.txt dans le sous-répertoire Sources. Ce fichier contient toutes les règles de compilation pour notre librairie. Pour utiliser notre librairie C++ dans un projet CMake, il suffit d'inclure ce fichier et de référencer notre librairie à l'aide du nom yoctolib.
Un petit exemple
Afin d'illustrer nos propos, nous allons voir toutes les étapes pour compiler le code suivant:
#include "yocto_api.h"
using namespace std;
int main(int argc, const char * argv[])
{
string errmsg;
if(YAPI::RegisterHub("usb", errmsg) != YAPI::SUCCESS) {
cerr << "RegisterHub error: " << errmsg << endl;
return 1;
}
cout << "Device list: " << endl;
YModule *module = YModule::FirstModule();
while (module != NULL) {
cout << module->get_serialNumber() << " ";
cout << module->get_productName() << endl;
module = module->nextModule();
}
YAPI::FreeAPI();
return 0;
}
Ce code affiche le numéro de série et le nom de produit de tous les modules Yoctopuce connectés sur les ports USB de la machine. Pour plus d'informations sur les fonctions utilisées dans cet exemple, vous pouvez vous référer à la documentation de la librairie C++. On sauve ce code dans un fichier main.cpp que l'on va compiler.
Pour compiler ce code, il faut que g++, CMake et la libusb-1.0-dev soient installés sur la machine. Sur une distribution basée Debian ou Ubuntu, il est possible d'installer tous ces packages à l'aide des commandes suivantes:
sudo apt-get update sudo apt-get install cmake sudo apt-get install build-essential gdb sudo apt-get install libusb-1.0-0-dev
Il faut ensuite télécharger la librairie C++ Yoctopuce. Cela peut être fait avec Git ou directement depuis notre site web. Le sous-répertoire Sources contient tous les fichiers source à compiler pour utiliser notre librairie ainsi que le fichier CMakeLists.txt qui sera utilisé par CMake.
Notez le path de ce répertoire car nous allons en avoir besoin plus loin. Dans notre cas, la librairie est décompressée dans le répertoire /home/yocto/Yoctolib.CPP/ et nous aurons donc besoin du path /home/yocto/Yoctolib.CPP/Source
Le fichier CMakeLists.txt
Maintenant que nous avons notre fichier main.cpp et toutes les dépendances installées sur la machine, on peut commencer à écrire le fichier CMakeLists.txt de notre application démo. Comme expliqué plus haut, ce fichier contient toutes les instructions pour compiler l'application.
On commencer par vérifier que la version installée de CMake est assez récente et donner un nom au projet, dans notre cas le projet s’appelle "Demo" et nous avons besoin de la version 3.16 de CMake.
cmake_minimum_required (VERSION 3.16) project (Demo)
Puis, on définit le nom de l’exécutable et les fichiers sources à compiler. Dans notre cas, le nom de l’exécutable est demo et il n'y a qu'un seul fichier source : main.cpp. Pas besoin d'ajouter les fichiers source de notre librairie C++, car nous allons inclure le fichier CMakeLists.txt de la librairie.
Il ne manque plus que les instructions pour inclure la librairie C++ Yoctopuce. Cette tâche est aisée car nous avons déjà un fichier CMakeLists.txt dans le sous-répertoire Source. Ce fichier contient la liste de tous les fichiers de la librairie à compiler ainsi que les flags à passer au compilateur ou au linker pour générer l’exécutable.
Attention : ce fichier est présent uniquement depuis la version 1.10.42060 de la librairie, s'il n'est pas présent il faut simplement utiliser une version plus récente de notre librairie.
La commande add_subdirectory avec le path du sous-répertoire Sources de la libraire permet d'ajouter la librairie. Dans notre cas, le path est /home/yocto/Yoctolib.CPP/Sources/. Le deuxième paramètre compiled_yoctolib définit un sous-répertoire que CMake va utiliser pour compiler la librairie.
Pour finir il faut spécifier que l’exécutable demo utilise la librairie Yoctopuce (Yoctolib).
Voici au le fichier CMakeLists.txt en entier:
cmake_minimum_required (VERSION 3.16)
project (Demo)
# Adds the executable called "demo" that is built from the source files "main.cpp".
add_executable (demo main.cpp)
# Adds the Sources subfolder of the Yoctopuce C++ library.
add_subdirectory (/home/yocto/Yoctolib.CPP/Sources/ compiled_yoctolib)
# Links the executable to the Yoctopuce C++ library (YoctoLib).
target_link_libraries (demo LINK_PUBLIC YoctoLib)
La compilation
Pour générer les fichiers de compilation, il faut exécuter cmake:
yocto@laptop-linux:~/tmp$ cmake . -- The C compiler identification is GNU 9.3.0 -- The CXX compiler identification is GNU 9.3.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/yocto/tmp
Pour compiler réellement l'application, il faut utiliser GNU make avec la commande make:
yocto@laptop-linux:~/tmp$ make Scanning dependencies of target YoctoLib [ 1%] Building CXX object compiled_yoctolib/CMakeFiles/YoctoLib.dir/yocto_accelerometer.cpp.o ... [ 97%] Linking CXX static library libYoctoLib.a [ 97%] Built target YoctoLib Scanning dependencies of target demo [ 98%] Building CXX object CMakeFiles/demo.dir/main.cpp.o [100%] Linking CXX executable demo [100%] Built target demo
Et voilà! l'application est compilée et peut être lancée avec la commande ./demo:
yocto@laptop-linux:~/tmp$ sudo ./demo Device list: YLTCHRL1-CD28D Yocto-LatchedRelay
Vous pouvez trouver sur GitHub le code source de cet exemple : https://github.com/yoctopuce-examples/cmake_example
Conclusion
CMake est un outil fort pratique quand on fait du C++. Il est plus convivial que GNU make. A titre de comparaison, le fichier CMakeLists.txt de notre librairie C++ ne fait que 14 lignes alors que le fichier GNU makefile en fait 938...