Génie Logiciel 1 |
GL1 TP3 - Compilation
Last update: 2023-08-22 |
- Outils de compilation
- Compilation séparée
- Construire un projet avec Make
- Autre utilisation de Make
- Gestion des dépendances avec Nix
- Intégrer des bibliothèques externes avec Pkg-config
- Compiler avec CMake
- Compiler des bibliothèques et des exécutables avec CMake
- Intégrer des bibliothèques externes avec CMake
- CMake et modules Git
- Analyse dynamique de code
Outils de compilation
Compilation séparée
Allez dans le dossier
ulco-gl1-etudiant/tp-compilation/hello
.Compilez le projet en une seule ligne de commande. Pensez aux options (fichier de sortie
say-hello
, warnings, optimisation…)Écrivez un script exécutable
compile.sh
qui effectue cette compilation.Quelles sont les différentes étapes de la «compilation» ? Recompilez le projet en réalisant chaque étape explicitement. Quel est l’intérêt de réaliser les différentes étapes séparément ?
Construire un projet avec Make
Comment utilise-t-on un Makefile pour compiler un projet ? Comment fonctionne le système de règle des Makefile ? Si besoin, consultez les deux premières sections de la doc gnu make.
Écrivez un Makefile basique pour compiler le projet
hello
(une règle par fichier objet/binaire à produire). Vérifiez que le projet compile bien et que seuls les fichiers nécessaires sont recompilés lors des modifications.Réécrivez votre Makefile en utilisant des règles automatiques et «flags» classiques (la gestion des dépendances envers les fichiers d’entête n’est pas demandée).
Autre utilisation de Make
Make est un outil très polyvalent, qui permet par exemple de compiler un projet, générer de la documentation, etc.
Allez dans le dossier
tp-compilation/progs
et regardez les fichiers fournis.Lancez un
make
et regardez les fichiers produits.Lancez un
make clean
.Ajoutez un fichier
prog2.cpp
, en vous inspirant deprog1.cpp
, et lancez unmake
.
Gestion des dépendances avec Nix
Quand on développe un projet, on ne code pas toutes les fonctionnalités de zéro : on réutilise du code existant ou des bibliothèques précompilées. Cependant il est souvent difficile de gérer ces dépendances, non seulement pour un développeur qui voudrait récupèrer le projet mais également pour un utilisateur qui voudrait installer le logiciel. Il existe de nombreux outils pour traiter ce problème : modules git, paquets linux (deb, rpm…), paquets universels (appimage, flatpak…), paquets de langages (conan, vcpkgs…)…
Ici, on va utiliser Nix, qui est le gestionnaire de paquets disponible dans la machine virtuelle fournie. Nix permet de configurer les dépendances d’un projet mais également de construire le projet, l’installer et le déployer.
- Allez dans le dossier
tp-compilation/people
. Vérifiez que, pour l’instant, il manque des dépendances et le projet ne compile pas.
$ c++ -Wall -Wextra -pthread -o people people.cpp
people.cpp:1:10: fatal error: 'csv.h' file not found
#include <csv.h>
^~~~~~~
1 error generated.
Regardez rapidement les fichiers d’extension
.nix
.Utilisation d’un environnement de développement : lancez un
nix-shell
, vérifiez que les dépendances sont récupérées automatiquement, compilez, testez puis quittez lenix-shell
.
$ nix-shell
these derivations will be built:
/nix/store/n94j008ma2pjlprqrmdjkg4cfm58swh8-fccp.drv
building '/nix/store/n94j008ma2pjlprqrmdjkg4cfm58swh8-fccp.drv'...
[nix-shell]$ c++ -Wall -Wextra -pthread -o people people.cpp
[nix-shell]$ ./people people.csv
John Doe (1970)
Haskell Curry (1900)
[nix-shell]$ exit
- Construction automatique : lancez un
nix-build
, vérifiez le résultat produit et testez. Attention,nix-build
reconstruit entièrement le projet et dans un nouveau dossier (cf/nix/store/
).
$ nix-build
these derivations will be built:
/nix/store/z7w7vfjmkplikm7swh90mjqzp10flszl-people.drv
building '/nix/store/z7w7vfjmkplikm7swh90mjqzp10flszl-people.drv'...
$ ./result/bin/people people.csv
John Doe (1970)
Haskell Curry (1900)
- Installation système : installez votre projet, testez, désinstallez, testez.
$ nix-env -if .
installing 'people'
these derivations will be built:
/nix/store/dgdnyv8hd1fvzmwaxgvr3vnjmjrn7ab6-people.drv
building '/nix/store/dgdnyv8hd1fvzmwaxgvr3vnjmjrn7ab6-people.drv'...
$ people people.csv
John Doe (1970)
Haskell Curry (1900)
$ nix-env -e people
uninstalling 'people'
$ people people.csv
people: command not found
Dans la suite du TP, les fichiers
.nix
nécessaires sont fournis et vous aurez juste à “travailler dans unnix-shell
” (ou à utiliser VSCode, comme on le verra dans le prochain TP).
Intégrer des bibliothèques externes avec Pkg-config
Lancez un
nix-shell
dans le dossiertp-compilation/hello-gtk
.Quelle est la bibliothèque utilisée par le projet ? Quels fichiers sont nécessaires et où sont-ils situés dans un système unix classique ?
Le programme
pkg-config
permet de récupérer des informations sur les bibliothèques (voir le guide pkg-config). Testez les options--list-all
,--cflags
et--libs
.Compilez le projet
hello-gtk
avec une commande utilisantpkg-config
. Indications : utilisez la notation “backtick” du bash.Complétez le
Makefile
de façon à pouvoir compiler le projet.N’oubliez pas de quitter le
nix-shell
une fois l’exercice terminé.
Compiler avec CMake
Le programme cmake
permet de générer un Makefile adapté au système courant, à
partir d’un autre type de fichier de configuration de projet
(CMakeLists.txt
). La compilation avec cmake
consiste donc à écrire un
CMakeLists.txt
, exécuter cmake
pour générer le Makefile
puis exécuter
make
pour compiler le projet. Voir le tutoriel
CMake.
Écrivez un
CMakeLists.txt
(de 3 lignes) pour le projethello
et compilez le projet avec les commandes suivantes.mkdir build cd build cmake .. make
Regardez la taille de l’exécutable produit avec un
ls -lh
. Supprimez le contenu du dossier debuild
et générez le projet en versionDebug
aveccmake -DCMAKE_BUILD_TYPE=Debug ..
. Regardez la taille du nouvel exécutable produit.Allez dans le dossier
tp-compilation/hello
et compilez avec la commandemake -C build -j4
(faites unclean
avant).
Compiler des bibliothèques et des exécutables avec CMake
Regardez le projet fourni dans le dossier
tp-compilation/mymaths
.Complétez la configuration
cmake
de façon à générer deux exécutablesapp1
etapp2
, en utilisant la bibliothèquemymaths
.Testez la compilation et les exécutables produits.
Intégrer des bibliothèques externes avec CMake
CMake permet d’intégrer des bibliothèques, via des paquets CMake ou via Pkg-config. Voir la doc de cmake.
Lancez un
nix-shell
danstp-compilation/play-videos
.Vérifiez que la compilation échoue, à cause de dépendances manquantes.
Modifiez le
CMakeLists.txt
de façon à ajouter les dépendances manquantes : modulessystem
etfilesystem
du paquet CMakeboost
, et paquets Pkg-configgtkmm-3.0
etlibvlc
.
CMake et modules Git
CMake permet de réutiliser des configurations, ce qui peut être pratique quand on utilise un module Git également configuré avec CMake.
Copiez le dossier
tp-compilation/webserver
dans~/webserver
puis lancez unnix-shell
dans~/webserver
.Regardez le fichier
CMakeLists.txt
.Ajoutez le projet https://github.com/an-tao/drogon via les modules Git. Utilisez l’option
--recursive
pour récupérer également les modules de ce projet.Compilez et testez le projet.
Analyse dynamique de code
Le principe du profilage de code est d’exécuter le programme à étudier tout en surveillant ce qu’il fait. Par exemple, gprof permet d’analyser les performances d’un programme en analysant les appels de fonctions. De même, valgrind permet d’analyser les appels de fonctions mais également la gestion mémoire.
Gestion mémoire
- Compilez le projet
badFibo
. Exécutez-le. Regardez rapidement le code source.
- Exécutez le programme via
valgrind
. Regardez et comprenez le rapport d’analyse.
$ valgrind ./badFibo 10
...
==1917== HEAP SUMMARY:
==1917== in use at exit: 124 bytes in 5 blocks
==1917== total heap usage: 7 allocs, 2 frees, 73,852 bytes allocated
==1917==
==1917== LEAK SUMMARY:
==1917== definitely lost: 124 bytes in 5 blocks
==1917== indirectly lost: 0 bytes in 0 blocks
==1917== possibly lost: 0 bytes in 0 blocks
==1917== still reachable: 0 bytes in 0 blocks
==1917== suppressed: 0 bytes in 0 blocks
- Corrigez le problème dans le code source et vérifiez avec une nouvelle analyse mémoire.
Temps d’exécution
- Mesurez le temps d’exécution avec
time
.
- Recompilez le projet en mode Release et retestez.
- Recompilez en mode RelWithDebInfo et faites une analyse de performance avec
valgrind
etkcachegrind
.
- Vérifiez que le temps est consommé par la fonction
fiboMod42
. Remplacez l’appel à cette fonction par un appel àmul42
et refaites une analyse.
Génie Logiciel 1 |