Tous droits réservés

Améliorer ses projets

Vous avez, au cours de cette troisième partie, énormément appris sur ce qu’être un développeur signifie. Bien entendu, il y a encore de nombreuses choses à apprendre et cette section ne pourra jamais être exhaustive. Il est temps pour nous de la conclure avec un dernier chapitre présentant quelques outils qui vous serons quasi-indispensables pour passer au niveau supérieur.

Ce chapitre va présenter plusieurs outils pour améliorer le développement de vos projets.

git — Sauvegarder et versionner son code

La problématique

Sauvegarder, c’est important. Peu importe qu’on parle de code, de photos, de documents, ne pas avoir de sauvegarde peut nous créer de gros problèmes quand un document est corrompu ou effacé par erreur. Ça nous est tous arrivé au moins une fois et c’est très embêtant.

Nos codes n’échappent pas à cette logique. Il est important de sauvegarder notre code régulièrement. Quand nos programmes sont tout petits, une solution consistant à copier/coller le dossier du projet peut suffire. Mais cette solution apporte en réalité plus d’inconvénients qu’autre chose.

  • Nous n’avons aucun moyen de voir l’historique des modifications d’un fichier.
  • C’est très lourd et encombrant puisqu’on se retrouve avec de plus en plus de dossiers.
  • Si deux dossiers ne contiennent pas les mêmes fichiers, les fusionner peut s’avérer complexe.
  • Dans le cas où on travaille à plusieurs sur le projet, impossible de savoir qui a quelle version.
  • En cas de bug, revenir à une ancienne version est complexe, voire impossible.

Heureusement et comme toujours, des gens très doués ont créé des outils adaptés, efficaces et il ne nous reste qu’à les utiliser. Ces outils s’appellent des gestionnaires de code source. Ils répondent à toutes les problématiques que nous avons soulevées plus haut. Le plus célèbre, utilisé et apprécié s’appelle git.

Installation

Dans le cas où vous êtes sous Windows, téléchargez la version la plus récente et installez-la dans le répertoire de votre choix. Pour ceux utilisant GNU/Linux, le paquet git est très certainement déjà installé. Dans le cas contraire, ce qui serait extrêmement étonnant, vous pouvez l’obtenir avec votre gestionnaire de paquet.

sudo apt install git

Bien qu’il existe des surcouches graphiques, je vous conseille d’apprendre à utiliser git en ligne de commande. De cette manière, vous serez autonomes peu importe le système d’exploitation ou l’environnement sur lesquels vous travaillerez, et vous en aurez une utilisation plus souple. Nous allons voir les bases dans ce cours, mais pour aller plus loin, il faudra vous baser sur des ressources externes. Je vous conseille notamment celle-ci, pour un guide de base, et le Pro Git Book, une référence très complète, et traduite en français qui plus est. :)

Outil fondamental

Git est vraiment un outil fondamental pour le développeur, il est très rentable de passer du temps à apprendre à le maîtriser. À la fin de ce cours, je vous suggère fortement de jeter un œil attentif au Pro Git Book.

Sous GNU/Linux, vous n’avez qu’à lancer les commandes directement depuis le terminal. Pour Windows, il faut lancer Git Bash, qui se trouve dans le dossier Git du Menu Démarrer.

Initialiser git

La première chose à faire est d'entrer un identifiant, une adresse mail et l’éditeur de votre choix. Cela permet de tracer qui a fait quelle modification. Les deux premières commandes à entrer sont les suivantes.

> git config --global user.name "nom"
> git config --global user.email mail
> git config --global core.editor Éditeur

Créer un dépôt

Maintenant, nous allons indiquer à git que nous voulons sauvegarder le dossier contenant notre code source. Il suffit de se positionner dans le répertoire voulu et de lancer la commande git init. Pour Windows, je procède ainsi, avec un projet Visual Studio en exemple.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 ~
$ cd /d/Documents/Visual\ Studio\ 2017/Projects/TestCpp/
$ git init

Pour GNU/Linux, faites de même. Je prends ici un simple répertoire qui contient mes sources.

informaticienzero@DESKTOP-GGDRVV5:~$ cd Documents/TestCpp
informaticienzero@DESKTOP-GGDRVV5:~/Documents/TestCpp$ git init

Votre projet est maintenant géré par git. C’est aussi simple que ça. :)

Connaître l’état de ses fichiers

Et si nous demandions à git de nous donner les fichiers modifiés ? Cela se fait très simplement en tapant git status. Pour le cas d’un projet fraichement initialisé, aucun fichier n’étant suivi, on obtient un message proche du message suivant.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git status
On branch master
No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        ZdSCpp/main.cpp

nothing added to commit but untracked files present (use "git add" to track)

Modifions donc un fichier quelconque. Dans mon cas, je supprime tout le contenu de main.cpp pour ne plus afficher qu’un message. Je relance la commande précédente et cette fois, il y a du changement.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   ZdSCpp/main.cpp

no changes added to commit (use "git add" and/or "git commit -a")

On voit bien que git a noté la modification du fichier main.cpp. Et si j’ajoute un nouveau fichier, comme un simple document texte ?

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   ZdSCpp/main.cpp

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        ZdSCpp/Fichier_texte.txt

no changes added to commit (use "git add" and/or "git commit -a")

Cette fois, il nous indique qu’un fichier non suivi a été ajouté. Cela signifie que git ne le versionnera pas et n’enregistrera pas son historique.

Ajouter un fichier

Il faut donc être en mesure de dire à git de suivre, ou de ne plus suivre, tel ou tel fichier. Dans le premier cas, cela se fait avec la commande git add nom_fichier.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git add ZdSCpp/Fichier_texte.txt

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   ZdSCpp/Fichier_texte.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   ZdSCpp/main.cpp

Le fichier ajouté se trouve maintenant sous la section « Changes to be committed », soit les changements à enregistrer. Au contraire, le fichier main.cpp ne le sera pas. Il faut l’ajouter lui aussi, pour que les modifications apportées à ce fichier soit elles aussi enregistrées.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git add ZdSCpp/main.cpp

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   ZdSCpp/Fichier_texte.txt
        modified:   ZdSCpp/main.cpp

Valider les modifications

Nous avons vérifié, tout est bon, nous voulons enregistrer ce que nous avons fait. On parle de commiter ou de faire un commit. On utilise la commande suivante git commit -m "Message", qui permet d’enregistrer les modifications avec un message explicatif.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git commit -m "Réécriture de main.cpp et ajout d'un document texte."
[master d83131f] Réécriture de main.cpp et ajout d'un document texte.
 2 files changed, 7 insertions(+), 13 deletions(-)
 create mode 100644 ZdSCpp/Fichier_texte.txt
 rewrite ZdSCpp/main.cpp (93%)
Message explicatif

Le message accompagnant le commit doit être de qualité, puisqu’il indique ce que vous avez fait. Des messages comme correction, xxx ou changement sont donc très mauvais puisqu’ils ne sont pas clairs du tout.

Voir l’historique

Vous pouvez voir l’évolution de votre code en demandant à git de vous afficher l’historique des commits. Dans notre cas, nous en avons trois. Le premier affiché est le dernier en date, celui que nous venons de faire. Les deux autres ont automatiquement été faits par git lors de l’initialisation du dépôt.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/ZdSCpp (master)
$ git log
commit d83131f1a0f860d40e06921c113affd16700c3e7 (HEAD -> master)
Author: informaticienzero <informaticienzero@mail.com>
Date:   Mon Mar 25 12:05:25 2019 +0100

    Réécriture de main.cpp et ajout d'un document texte.

commit 242b99d89769b2d409213db3d25c1f60c6c9088a
Author: informaticienzero <informaticienzero@mail.com>
Date:   Sun Mar 24 12:13:46 2019 +0100

    Ajoutez des fichiers projet.

commit 40f39687c1ad0ef616c7d6fae8549865cb5c4c54
Author: informaticienzero <informaticienzero@mail.com>
Date:   Sun Mar 24 12:13:42 2019 +0100

    Ajoutez les fichiers .gitignore et .gitattributes.

Notez que l’auteur et la date sont affichés, ainsi que le checksum, la somme de contrôle identifiant de manière unique chaque commit.

Bloquer certains fichiers

Si versionner le code est une bonne pratique, certains fichiers ne doivent pas être intégrés au dépôt. C’est le cas des fichiers objets, entre autres. Ceux-ci sont des produits de la compilation, donc rapidement périmés, pas adaptés en cas de passage à un autre système d’exploitation ou un autre compilateur, etc. On veut donc les exclure. De même, on n’inclut généralement pas les exécutables, les fichiers de configuration de l’éditeur utilisé, etc.

Pour ce faire, on dispose d’un fichier .gitignore, un bête fichier texte qui indique à git que certains fichiers ou certaines extensions sont à exclure. Il suffit de le créer et d’ajouter dedans les règles souhaitées. Par exemple, exclure tous les fichiers objets avec l’extension .o se fait en ajoutant la ligne *.o.

Astuce Windows

Si vous tentez de créer un fichier nommé .gitignore avec l’explorateur Windows, celui-ci protestera que vous n’avez pas entré de nom de fichier. Une astuce consiste à créer un fichier s’appelant .gitignore. (notez le point final supplémentaire), que Windows va automatiquement renommer correctement.

Dans le cas d’un projet Visual Studio, je me mets à la racine du projet, dans le même dossier où se trouve la solution .sln et je crée le fichier .gitignore. Les valeurs que je mets dedans sont celles que Visual Studio recommande, que j’ai pris de précédents projets et que je vous mets ci-dessous. On retrouve notamment les dossiers Debug et Release qui sont exclus, ainsi que les fichiers objets .obj.

Fichier .gitignore pour Visual Studio
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# DNX
project.lock.json
project.fragment.lock.json
artifacts/

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
*.mdf
*.ldf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

Pour GNU/Linux, pareil, créer ce fichier puis ajouter dedans les lignes ci-dessous.

Fichier .gitignore pour GNU/Linux
# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

Je vous fournis ici des fichiers pré-remplis, mais quand vous aurez acquis de l’expérience, vous saurez les adapter à vos projets et vos contraintes.

Exemple concret

Je suis sous GNU/Linux et je compile un fichier source pour obtenir mon programme. Sans fichier .gitignore, mon exécutable est inclus aussi et je ne veux pas.

informaticienzero@DESKTOP-GGDRVV5:~/Documents/TestCpp$ git status
Sur la branche master

Aucun commit

Modifications qui seront validées :
  (utilisez "git rm --cached <fichier>..." pour désindexer)

        nouveau fichier : main.cpp
        nouveau fichier : programme.out

Si je crée mon fichier .gitignore comme vu juste avant, cette fois, mon exécutable est bien exclu et je peux commiter mon code.

informaticienzero@DESKTOP-GGDRVV5:~/Documents/TestCpp$ git status
Sur la branche master

Aucun commit

Modifications qui seront validées :
  (utilisez "git rm --cached <fichier>..." pour désindexer)

        nouveau fichier : .gitignore
        nouveau fichier : main.cpp

Aller plus loin

Comment faire pour supprimer un fichier ? Comment revenir à un commit précédent ? Qu’est-ce que le concept de branches et comment l’utiliser ? Toutes ces questions trouvent leurs réponses dans le Pro Git Book, que je vous encourage une fois de plus à lire. Il est d’excellente qualité, progressif et vous enseignera tout ce que vous devez savoir sur git.

Visual Studio

Il est possible de gérer son code source avec git directement depuis Visual Studio. Regardez si vous avez la même petite ligne en bas à droite.

Avez-vous cette ligne ?
Avez-vous cette ligne ?

Si ce n’est pas le cas, il suffit d’installer une extension. Dans le menu Démarrer, cherchez le programme qui s’appelle Visual Studio Installer. Ce programme accompagne Visual Studio 2019 et permet d’installer des mises à jour et des composants supplémentaires.

Cliquez sur Modifier -> Composants individuels, puis descendez tout en bas chercher la ligne GitHub Extension for Visual Studio. Cochez-la et cela lancera son installation. Une fois fini, rouvrez Visual Studio, puis votre projet et vous verrez vous aussi la même ligne que moi.

Cliquez dessus, sélectionnez git et voilà, votre projet est géré par git lui aussi. Dans l’onglet Team Explorer en haut à droite, vous pouvez faire les mêmes opérations que nous avons vu plus haut, directement dans Visual Studio, sans passer par la console.

Je peux ici taper mon message de commit, voir les fichiers modifiés puis valider.
Je peux ici taper mon message de commit, voir les fichiers modifiés puis valider.

Le guide officiel contient une page dédiée au sujet.

GitHub — Partager son code

La problématique

Notez que, dans le nom de cet outil, on retrouve Git. C’est normal, car les deux outils sont fortement liés. Si Git permet de sauvegarder l’état de son code, d’en vérifier l’historique, d’annuler ou de retravailler des commits, etc, il n’en reste pas moins que votre code n’est disponible que sur votre ordinateur. GitHub est là en complément.

GitHub est un service en ligne qui permet d'héberger ses dépôts. Puisque ceux-ci sont sur Internet, librement disponibles, vous êtes en mesure de partager votre code avec le monde entier. D’autres personnes peuvent ainsi le récupérer, le modifier et envoyer les modifications. C’est le fonctionnement et la base des projets dits open-source. Par exemple, Zeste de Savoir, le site sur lequel vous lisez ce cours, utilise GitHub pour stocker son code source et permettre à plusieurs développeurs de collaborer.

Parmi les autres avantages qu’on peut citer, utiliser un service en ligne nous protège des pannes et autres effacements sur notre poste de travail. Si demain votre disque dur meurt, le fait d’utiliser git seul pour versionner un projet ne vous sera d’aucune aide. Par contre, s’il est hébergé sur un service en ligne, comme GitHub, il suffira de récupérer les sources et le développement peut repartir.

Conseil

Lors de la création de votre compte, utilisez la même adresse mail que vous avez utilisé lors de la configuration de git.

Création d’un projet

Je vais partir du principe que vous avez créé votre compte et que tout est bon. La première étape est de créer un nouveau projet. Pour illustrer le principe, nous allons créer un projet Discographie, pour permettre de sauvegarder et partager le code du T.P de la partie II du cours.

Ma page est noire parce que j'ai un thème foncé activé, mais sinon les informations contenues dedans sont les mêmes.
Ma page est noire parce que j'ai un thème foncé activé, mais sinon les informations contenues dedans sont les mêmes.

Plusieurs choses sont à indiquer.

  • Le nom du projet.
  • Une courte description, qui indique à quoi on a affaire.
  • Le choix de la visibilité. Public signifie que tout le monde verra votre projet, alors que private permet de la restreindre à vous et aux utilisateurs que vous autoriserez.
  • Initialize this repository with a README permet de créer, en plus du projet, le fameux fichier README, qui contient souvent la description du projet, les aspects légaux, les informations d’installation, etc.
  • On peut ajouter également un fichier .gitignore et une licence. Le premier, vous connaissez. Le deuxième indique sous quels termes vous souhaitez partager votre code. Certaines licences permettent de réutiliser le code dans des applications payantes alors que d’autres l’interdisent, etc. De très nombreuses variantes sont disponibles, mais tout ça ne nous intéresse pas dans notre cas.

Quand tout est bon, vous n’avez plus qu’à cliquer sur le bouton vert Create repository. Voici le mien.

On va partir du principe que vous avez initialisé le dépôt localement, créé un .gitignore et que tout est commité.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/Discographie (master)
$ git ls-files
.gitattributes
.gitignore
Discographie.sln
Discographie/Discographie.vcxproj
Discographie/Discographie.vcxproj.filters
Discographie/discographie.cpp
Discographie/discographie.hpp
Discographie/donnees_disco.cpp
Discographie/donnees_disco.hpp
Discographie/donnees_disco_tests.cpp
Discographie/donnees_disco_tests.hpp
Discographie/main.cpp
Discographie/systeme_commandes.cpp
Discographie/systeme_commandes.hpp
Discographie/utils.cpp
Discographie/utils.hpp

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/Discographie (master)
$ git status
On branch master
nothing to commit, working tree clean

Il faut maintenant indiquer à git où se trouve le répertoire distant dans lequel nous voulons stocker le code et que nous venons de créer. Cela se fait avec la commande git remote add origin URL, où URL est l’adresse de votre dépôt. Celle-ci s’obtient en cliquant sur le bouton vert Clone or Download.

L'URL de mon projet.
L'URL de mon projet.
informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/Discographie (master)
$ git remote add origin https://github.com/informaticienzero/TutorielCpp-Discographie.git

Récupérer localement les modifications

Maintenant qu’on est connecté avec le dépôt distant, nous sommes capables de récupérer des modifications faites par d’autres. Dans notre cas, personne d’autre n’a touché au projet, mais comme nous avons créé un fichier README, qui n’est pas présent localement, il faut se synchroniser. C’est ce que la commande git pull origin master --allow-unrelated-histories -m "Message" fait.

L’option origin désigne le dépôt distant et master représente la branche sur laquelle on travaille, celle par défaut. Quant au message, il résume le pourquoi de l’opération.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/Discographie (master)
$ git pull origin master --allow-unrelated-histories -m "Récupération du dépôt distant."
From https://github.com/informaticienzero/TutorielCpp-Discographie
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 README.md | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 README.md

Dans le cas où vous travaillez à plusieurs sur le même dépôt distant, il est important de régulièrement récupérer les modifications des autres, pour vous assurer que vous restez à jour et pour que la gestion des conflits (deux modifications du même fichier) soit plus simple.

Pousser nos modifications

Il ne reste plus que l’étape consistant à pousser nos modifications sur le dépôt distant. Celle-ci se fait avec la commande git push origin master.

informaticienzero@DESKTOP-GGDRVV5 MINGW64 /d/Documents/Visual Studio 2017/Projects/Discographie (master)
$ git push origin master
Counting objects: 23, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (23/23), done.
Writing objects: 100% (23/23), 10.25 KiB | 2.56 MiB/s, done.
Total 23 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/informaticienzero/TutorielCpp-Discographie.git
   a496595..d0535ce  master -> master

Actualisez votre page GitHub et vous verrez que le code est apparu. Félicitations, votre code est maintenant publiquement disponible et accessible à tous. :)

Ma page GitHub après avoir poussé mes modifications.
Ma page GitHub après avoir poussé mes modifications.

Aller plus loin

Nous n’avons fait que découvrir une fonctionnalité, importante certes, mais basique de GitHub. Il vous reste encore beaucoup à apprendre. Comme ce service est très populaire, vous trouverez beaucoup de tutoriels et d’aide sur Internet. Je vous encourage à commencer par le guide officiel.

Dans celui-ci, vous apprendrez notamment à récupérer les projets des autres (on appelle ça forker), à leur proposer des modifications (des pull requests), à ouvrir et traiter des rapports de bugs (des issues) et bien d’autres choses encore.

CMake — Automatiser la compilation de nos programmes

La problématique

Nous avons du code versionné, en ligne pour plus de sécurité et d’accessibilité et c’est déjà très bien. Mais si je n’ai pas le même environnement ? Dans la partie précédente, le projet posté sur GitHub a été développé avec Visual Studio. Vais-je devoir taper plusieurs lignes de commandes pour le compiler chez moi ? C’est assez galère, avouons-le. Et dans le cas de projets complexes comme Boost, ça peut être difficile de savoir quelles commandes écrire.

CMake fait partie de la famille des outils permettant ce qu’on appelle en anglais du build automation, soit de l’automatisation de la compilation. Il est disponible notamment pour GNU/Linux et Windows, ce qui le rend intéressant, car à partir d’un fichier d’instructions écrit dans un langage propre à CMake, l’outil est capable de générer les instructions de compilation, selon le système d’exploitation et le compilateur utilisés, sans que l’on ait à s’occuper de quoi que ce soit. Il est capable de compiler d’autres langages que C++, donc apprendre à l’utiliser vous sera utile même en dehors de ce tutoriel.

Un exemple simple

Reprenons, dans un dossier à part, nos fichiers d’en-têtes et sources qui composent le projet Discographie, puis ajoutons un fichier CMakeLists.txt, qui est le fichier expliquant comment compiler notre projet. La première chose à faire est de définir quelle version minimale de CMake est autorisée. Cela permet d’imposer l’utilisation d’une version récente, ce qui est nécessaire pour compiler en C++17.

cmake_minimum_required (VERSION 3.10.0)

Ensuite, autre étape importante, le nom du projet. Dans notre cas, il est tout trouvé.

project (Discographie)

Maintenant, il faut lister les fichiers qui constituent notre projet, en les séparant entre fichiers d’en-têtes et fichiers sources. CMake utilise des variables pour ça. On va définir, grâce à la fonction set, une variable HEADERS regroupant tous nos fichiers d’en-têtes et une variable SOURCES regroupant les fichiers sources.

set (HEADERS
    discographie.hpp
    donnees_disco.hpp
    donnees_disco_tests.hpp
    systeme_commandes.hpp
    utils.hpp
)

set (SOURCES
    discographie.cpp
    donnees_disco.cpp
    donnees_disco_tests.cpp
    systeme_commandes.cpp
    utils.cpp
    main.cpp
)

Terminons en indiquant comment construire une sortie nommée Discographie, en utilisant nos variables préalablement définies. La ligne juste au-dessus indique qu’on veut que CMake configure sa sortie pour utiliser C++17.

set (CMAKE_CXX_STANDARD 17)
add_executable (Discographie ${SOURCES} ${HEADERS})

Au final, voilà le CMakeLists.txt qu’on obtient, avec commentaires en prime.

# On n'autorise l'utilisation qu'à partir de la version 3.10.0.
cmake_minimum_required (VERSION 3.10.0)

# Il s'agit du projet Discographie.
project (Discographie)

# Les fichiers d'en-tête.
set (HEADERS
    discographie.hpp
    donnees_disco.hpp
    donnees_disco_tests.hpp
    systeme_commandes.hpp
    utils.hpp
)

# Les fichiers sources.
set (SOURCES
    discographie.cpp
    donnees_disco.cpp
    donnees_disco_tests.cpp
    systeme_commandes.cpp
    utils.cpp
    main.cpp
)

# C++17
set (CMAKE_CXX_STANDARD 17)
# On veut un exécutable Discographie compilé à partir des fichiers décrits par SOURCES et HEADERS.
add_executable (Discographie ${SOURCES} ${HEADERS})

Il ne reste plus qu’à tester en lançant cmake avec la commande ci-dessous. Dans mon cas, sous Windows j’obtiens un fichier .sln, c’est-à-dire une solution Visual Studio qu’il n’y a plus qu’à ouvrir et compiler, en 32 bits. Pour du 64 bits, il faut remplacer -A Win32 par -A x64

PS D:\Téléchargements\Tests> cmake . -G "Visual Studio 15 2017" -A Win32
-- Building for: Visual Studio 15 2017
-- The C compiler identification is MSVC 19.16.27027.1
-- The CXX compiler identification is MSVC 19.16.27027.1
-- Check for working C compiler: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe
-- Check for working C compiler: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe -- 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: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe
-- Check for working CXX compiler: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe -- 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: D:/Téléchargements/Tests

Sous GNU/Linux, on obtient un fichier Makefile, qu’il n’y a plus qu’à exécuter en lançant la commande make, qui va construire l’exécutable.

informaticienzero@DESKTOP-GGDRVV5:~/Documents/TutorielCpp-Discographie/Discographie$ cmake -g CMakeLists.txt
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.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/informaticienzero/Documents/TutorielCpp-Discographie/Discographie

informaticienzero@DESKTOP-GGDRVV5:~/Documents/TutorielCpp-Discographie/Discographie$ make
[ 14%] Building CXX object CMakeFiles/Discographie.dir/discographie.cpp.o
[ 28%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco.cpp.o
[ 42%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco_tests.cpp.o
[ 57%] Building CXX object CMakeFiles/Discographie.dir/systeme_commandes.cpp.o
[ 71%] Building CXX object CMakeFiles/Discographie.dir/utils.cpp.o
[ 85%] Building CXX object CMakeFiles/Discographie.dir/main.cpp.o
[100%] Linking CXX executable Discographie
[100%] Built target Discographie

Dans le cas où vous avez Qt Creator d’installé, nous allons nous baser sur le compilateur fourni avec, MinGW. Pour que CMake puisse l’utiliser, il faut lancer la console inclue avec Qt. Dans mon cas, elle se trouve dans Menu Démarrer -> Qt -> 5.12.2 -> MinGW 7.3.0 (32 bit) -> Qt 5.12.2 (MinGW 7.3.0 32-bit). Le chemin est à adapter en fonction de votre version de Qt, notamment.

Maintenant, on précise à CMake que l’on veut utiliser "MinGW Makefiles", ce qui va produire un fichier Makefile, comme sous l’environnement GNU/Linux.

Pour MinGW

Petite particularité concernant MinGW, il faut d’abord ajouter la ligne suivante dans le fichier CMakeLists.txt, avant la ligne add_executable.

set (CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")

En sortie, j’obtiens le résultat suivant. Le code est généré en lançant mingw32-make.

C:\Users\informaticienzero\Downloads\Discographie>cmake . -G "MinGW Makefiles"
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: C:/Programmation/Qt/Tools/mingw730_32/bin/gcc.exe
-- Check for working C compiler: C:/Programmation/Qt/Tools/mingw730_32/bin/gcc.exe -- 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: C:/Programmation/Qt/Tools/mingw730_32/bin/g++.exe
-- Check for working CXX compiler: C:/Programmation/Qt/Tools/mingw730_32/bin/g++.exe -- 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: C:/Users/benbo/Downloads/Discographie

C:\Users\informaticienzero\Downloads\Discographie>mingw32-make
Scanning dependencies of target Discographie
[ 14%] Building CXX object CMakeFiles/Discographie.dir/discographie.cpp.obj
[ 28%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco.cpp.obj
[ 42%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco_tests.cpp.obj
[ 57%] Building CXX object CMakeFiles/Discographie.dir/systeme_commandes.cpp.obj
[ 71%] Building CXX object CMakeFiles/Discographie.dir/utils.cpp.obj
[ 85%] Building CXX object CMakeFiles/Discographie.dir/main.cpp.obj
[100%] Linking CXX executable Discographie.exe
[100%] Built target Discographie

Lier des bibliothèques externes

Très bien, nous sommes capables de compiler notre projet peu importe la plateforme. C’est déjà une très bonne base. Mais allons plus loin en intégrant une bibliothèque externe, Boost. Je veux en effet pouvoir utiliser Boost.Log dans mon fichier main.cpp.

#include "donnees_disco_tests.hpp"
#include "discographie.hpp"
#include "systeme_commandes.hpp"
#include "utils.hpp"

#include <stdexcept>
#include <boost/log/trivial.hpp>

int main()
{
    // ... 

    BOOST_LOG_TRIVIAL(info) << "Lancement du projet Discographie.";
    
    bool continuer { true };
    do
    {
        // Du code.

    } while (continuer);

    BOOST_LOG_TRIVIAL(info) << "Fin du programme.";
    return 0;
}

La première chose qu’il faut prendre en compte, ce sont les différences entre Windows et GNU/Linux. Eh oui, Boost n’est pas installé au même endroit selon le système d’exploitation utilisé. Heureusement, CMake permet de préciser des instructions pour un système d’exploitation ou un compilateur en particulier.

Liaison statique

Commençons par définir une variable bien utile pour la suite, qui indique qu’on veut lier statiquement Boost à notre programme. Cela se fait toujours avec le mot-clé set.

set (Boost_USE_STATIC_LIBS ON)

GNU/Linux

Ensuite, configurons les spécificités de GNU/Linux. Pour ça, rien de compliqué, un simple if (UNIX) suffit. Notez la présence d’un ENDIF (UNIX), qui clôt le bloc conditionnel de la même manière que nos accolades en C++.

if (UNIX)

endif (UNIX)

De quoi a t-on besoin ? Il existe un module qui cherche spécifiquement Boost sur le système où CMake est installé. On l’utilise comme suit, en remplaçant composants par les parties de Boost dont nous avons besoin.

find_package (Boost COMPONENTS composants REQUIRED)

Souvenez-vous du chapitre précédent, nous avions besoin non seulement de log et log_setup, mais également de system et de thread. La commande à écrire est donc la suivante.

if (UNIX)
    find_package (Boost COMPONENTS log log_setup system thread REQUIRED)
endif (UNIX)

Visual Studio

Rien de bien méchant pour la configuration de MSVC, le doux nom du compilateur fourni avec Visual Studio. À noter que seuls log et log_setup sont requis.

# Configuration pour Windows avec Visual Studio.
if (MSVC)
    set (BOOST_ROOT "C:/Programmation/Boost.1.69/boost")
    set (BOOST_INCLUDEDIR "C:/Programmation/Boost.1.69")
    # Avec Visual Studio, seuls log et log_setup sont requis.
    find_package (Boost COMPONENTS log log_setup REQUIRED)
endif (MSVC)

Qt Creator

Comme Qt Creator utilise notamment MinGW, on va demander à ce que CMake fasse de même. Et la première chose est de lui indiquer où se trouve l’exécutable make, qui permet de produire l’exécutable depuis le fichier Makefile généré par CMake. Ce chemin est bien entendu à adapter en fonction de l’endroit où Qt Creator est installé.

if (MINGW)
    set (CMAKE_PREFIX_PATH "C:/Programmation/Qt/Tools/mingw730_64/bin")
endif (MINGW)

Une autre variable est à créer à cause d’un bug. Sans cette variable, CMake ne trouvera pas nos bibliothèques 64 bits. Bien entendu, cela n’est valable que si vous utilisez la version 64 bits de la bibliothèque.

if (MINGW)
    set (CMAKE_PREFIX_PATH "C:/Programmation/Qt/Tools/mingw730_64/bin")
    set (Boost_ARCHITECTURE "-x64")
endif (MINGW)

Comme pour Visual Studio, il faut préciser le dossier contenant Boost, ainsi que les fichiers d’en-tête, puis appeler la commande find_package.

if (MINGW)
    set (CMAKE_PREFIX_PATH "C:/Programmation/Qt/Tools/mingw730_64/bin")
    set (Boost_ARCHITECTURE "-x64")

    set (BOOST_ROOT "C:/Boost")
    set (BOOST_INCLUDEDIR "C:/Boost/include/boost-1_69")
    find_package (Boost COMPONENTS log log_setup thread REQUIRED)
endif (MINGW)

A-t-on trouvé Boost ?

Il est important de gérer le cas où Boost ne serait pas présent ou pas trouvé. Heureusement, c’est très simple. Quand la commande find_package est invoquée pour trouver une bibliothèque, elle a défini une variable XXX_FOUND, un booléen indiquant si oui ou non la bibliothèque demandée est présente. Dans notre cas, c’est Boost_FOUND.

if (NOT Boost_FOUND)

else ()

endif (NOT Boost_FOUND)

Dans le cas où Boost est introuvable, il faut afficher un message d’erreur. La commande message prend justement un niveau d’erreur ainsi que le message à afficher.

if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

endif (NOT Boost_FOUND)

Dans le cas contraire, on peut afficher les chemins des fichiers d’en-têtes et objets, par exemple. Cela se fait en affichant Boost_INCLUDE_DIRS et Boost_LIBRARY_DIRS.

if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

    message (STATUS "Boost Fichiers en-têtes - ${Boost_INCLUDE_DIRS}")
    message (STATUS "Boost Fichiers objets - ${Boost_LIBRARY_DIRS}")

endif (NOT Boost_FOUND)

Inclure les fichiers nécessaires

Ces deux variables ne sont pas juste là pour être affichées. Pour que notre programme soit correctement généré, il faut qu’on lui indique les fichiers d’en-têtes et objets à inclure. C’est justement ce que font les commandes include_directories et link_directories.

if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

    message (STATUS "Boost Fichiers en-têtes - ${Boost_INCLUDE_DIRS}")
    message (STATUS "Boost Fichiers objets - ${Boost_LIBRARY_DIRS}")

    include_directories (${Boost_INCLUDE_DIRS})
    link_directories (${Boost_LIBRARY_DIRS})

endif (NOT Boost_FOUND)

La construction de l’exécutable

Comme dans l’étape précédente, nous voulons configurer le programme pour qu’il soit compilé avec C++17. Les deux commandes vues plus haut, dans l’exemple simple, ne changent donc pas.

if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

    message (STATUS "Boost Fichiers en-têtes - ${Boost_INCLUDE_DIRS}")
    message (STATUS "Boost Fichiers objets - ${Boost_LIBRARY_DIRS}")

    include_directories (${Boost_INCLUDE_DIRS})
    link_directories (${Boost_LIBRARY_DIRS})

    set (CMAKE_CXX_STANDARD 17)
    add_executable (Discographie ${SOURCES})

endif (NOT Boost_FOUND)

Il ne reste plus qu’à lier Boost à notre exécutable. Cette étape nécessite elle aussi une séparation entre Windows et GNU/Linux. En effet, la façon d’ajouter les bibliothèques n’est pas la même et GNU/Linux réclame une option supplémentaire.

if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

    message (STATUS "Boost Fichiers en-têtes - ${Boost_INCLUDE_DIRS}")
    message (STATUS "Boost Fichiers objets - ${Boost_LIBRARY_DIRS}")

    include_directories (${Boost_INCLUDE_DIRS})
    link_directories (${Boost_LIBRARY_DIRS})

    set (CMAKE_CXX_STANDARD 17)
    add_executable (Discographie ${SOURCES})

    if (UNIX)

    else ()
    
    endif (UNIX)

endif (NOT Boost_FOUND)

Dans les deux cas, on utilise la commande target_link_library. Pour Windows, c’est simple, il suffit de donner le chemin des fichiers objets, c’est-à-dire Boost_LIBRARY_DIRS. Pour GNU/Linux, il faut rechercher une bibliothèque supplémentaire, -lpthread, puis préciser quelles bibliothèques sont précisément requises.

Parallèle

Ce qui se passe ici est en fait la même chose que ce que nous faisons manuellement au chapitre précédent.

Je vous mets donc les commandes nécessaires ci-dessous.

if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

    message (STATUS "Boost Fichiers en-têtes - ${Boost_INCLUDE_DIRS}")
    message (STATUS "Boost Fichiers objets - ${Boost_LIBRARY_DIRS}")

    include_directories (${Boost_INCLUDE_DIRS})
    link_directories (${Boost_LIBRARY_DIRS})

    set (CMAKE_CXX_STANDARD 17)
    add_executable (Discographie ${SOURCES})

    if (UNIX)
        set (THREADS_PREFER_PTHREAD_FLAG ON)
        find_package (Threads REQUIRED)
        target_link_libraries (Discographie -static Threads::Threads Boost::system Boost::log Boost::log_setup Boost::thread)
    else ()
        target_link_libraries (Discographie ${Boost_LIBRARIES})
    endif (UNIX)

endif (NOT Boost_FOUND)

Fichier final

Voici le fichier au final, commenté et complet.

# On n'autorise l'utilisation qu'à partir de la version 3.0.
cmake_minimum_required(VERSION 3.10)

# Il s'agit du projet Discographie.
project (Discographie)

# Couleurs en sortie pour les Makefiles sur GNU/Linux.
set (CMAKE_COLOR_MAKEFILE ON)

# Les fichiers d'en-tête.
set (HEADERS
    discographie.hpp
    donnees_disco.hpp
    donnees_disco_tests.hpp
    systeme_commandes.hpp
    utils.hpp
)

# Les fichiers sources.
set (SOURCES
    discographie.cpp
    donnees_disco.cpp
    donnees_disco_tests.cpp
    systeme_commandes.cpp
    utils.cpp
    main.cpp
)

# On veut lier Boost de façon statique.
set (Boost_USE_STATIC_LIBS ON)

# Configuration pour GNU/Linux et les UNIX.
if (UNIX)
    set (BOOST_ROOT "/user/include/boost")
    set (BOOST_INCLUDEDIR "/user/include/boost")
    # Utiliser Boost.Log réclame plusieurs bibliothèques sous GNU/Linux.
    find_package (Boost COMPONENTS log log_setup system thread REQUIRED)
endif (UNIX)

# Configuration pour Windows avec Visual Studio.
if (MSVC)
    set (BOOST_ROOT "C:/Programmation/Boost.1.69/boost")
    set (BOOST_INCLUDEDIR "C:/Programmation/Boost.1.69")
    # Avec Visual Studio, seuls log et log_setup sont requis.
    find_package (Boost COMPONENTS log log_setup REQUIRED)
endif (MSVC)

# Configuration pour Windows avec Qt Creator.
if (MINGW)
    # Cas particulier, pour indiquer où se trouve make.
    set (CMAKE_PREFIX_PATH "C:/Programmation/Qt/Tools/mingw730_64/bin")
    # Pour utiliser les bibliothèques 64 bits.
    set (Boost_ARCHITECTURE "-x64")
    
    set (BOOST_ROOT "C:/Boost")
    set (BOOST_INCLUDEDIR "C:/Boost/include/boost-1_69")
    # Avec Qt Creator, il faut aussi ajouter thread.
    find_package (Boost COMPONENTS log log_setup thread REQUIRED)
endif (MINGW)

# Teste si Boost a bien été trouvé.
if (NOT Boost_FOUND)
    message (FATAL_ERROR "Erreur : Boost est introuvable !")
else ()

    message (STATUS "Boost Fichiers en-têtes - ${Boost_INCLUDE_DIRS}")
    message (STATUS "Boost Fichiers objets - ${Boost_LIBRARY_DIRS}")

    include_directories (${Boost_INCLUDE_DIRS})
    link_directories (${Boost_LIBRARY_DIRS})
    
    # C++17
    set (CMAKE_CXX_STANDARD 17)
    # On veut un exécutable Discographie compilé à partir des fichiers décrits par SOURCES et HEADERS.
    add_executable (Discographie ${SOURCES})

    # Les options pour lier l'exécutable et Boost sont différentes selon Windows ou GNU/Linux.
    if (UNIX)
        set (THREADS_PREFER_PTHREAD_FLAG ON)
        # Requis pour GNU/Linux.
        find_package (Threads REQUIRED)
        target_link_libraries (Discographie -static Threads::Threads Boost::system Boost::log Boost::log_setup Boost::thread)
    else ()
        target_link_libraries (Discographie ${Boost_LIBRARIES})
    endif (UNIX)

endif (NOT Boost_FOUND)

Exécuter CMake

Maintenant que le fichier CMakeLists.txt est prêt, alors il ne nous reste plus qu’à lancer la génération de notre programme. Voici comment je construis le programme avec Boost 32 bits. J’obtiens une solution .sln prête à être compilée et exécutée.

PS D:\Téléchargements\Tests> cmake . -G "Visual Studio 15 2017" -A Win32
-- The C compiler identification is MSVC 19.16.27027.1
-- The CXX compiler identification is MSVC 19.16.27027.1
-- Check for working C compiler: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe
-- Check for working C compiler: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe -- 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: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe
-- Check for working CXX compiler: C:/Programmation/Visual Studio 2017 Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - not found
-- Found Threads: TRUE
-- Boost version: 1.69.0
-- Found the following Boost libraries:
--   log
--   log_setup
--   date_time
--   filesystem
--   thread
--   regex
--   chrono
--   atomic
-- Boost Fichier en-têtes - C:/Programmation/Boost.1.69
-- Boost Fichiers objets - C:/Programmation/Boost.1.69/lib32-msvc-14.1
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Téléchargements/Tests

Sous GNU/Linux, j’obtiens un fichier Makefile qu’il ne reste plus qu’à lancer en appelant make. J’obtiens au final mon programme fonctionnel.

informaticienzero@DESKTOP-GGDRVV5:~/Documents/TutorielCpp-Discographie/Discographie$ cmake -g CMakeLists.txt
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.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
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   log
--   log_setup
--   system
--   thread
--   date_time
--   filesystem
--   regex
--   chrono
--   atomic
-- Boost Fichier en-têtes - /usr/include
-- Boost Fichiers objets - /usr/lib/x86_64-linux-gnu
-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes
-- Configuring done
-- Generating done
-- Build files have been written to: /home/informaticienzero/Documents/TutorielCpp-Discographie/Discographie
informaticienzero@DESKTOP-GGDRVV5:~/Documents/TutorielCpp-Discographie/Discographie$ make
Scanning dependencies of target Discographie
[ 14%] Building CXX object CMakeFiles/Discographie.dir/discographie.cpp.o
[ 28%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco.cpp.o
[ 42%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco_tests.cpp.o
[ 57%] Building CXX object CMakeFiles/Discographie.dir/systeme_commandes.cpp.o
[ 71%] Building CXX object CMakeFiles/Discographie.dir/utils.cpp.o
[ 85%] Building CXX object CMakeFiles/Discographie.dir/main.cpp.o
[100%] Linking CXX executable Discographie
[100%] Built target Discographie
informaticienzero@DESKTOP-GGDRVV5:~/Documents/TutorielCpp-Discographie/Discographie$ ./Discographie
[2019-03-26 16:22:56.944143] [0x000000000220c900] [info]    Lancement du programme Discothèque.
> quitter
[2019-03-26 16:23:02.046525] [0x00001d30] [info]    Fin du programme. 

Avec MinGW, pareil, je relance une console Qt et j’exécute la commande cmake avec les bons paramètres.

C:\Users\informaticienzero\Downloads\Discographie>cmake . -G "MinGW Makefiles"
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: C:/Programmation/Qt/Tools/mingw730_64/bin/gcc.exe
-- Check for working C compiler: C:/Programmation/Qt/Tools/mingw730_64/bin/gcc.exe -- 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: C:/Programmation/Qt/Tools/mingw730_64/bin/g++.exe
-- Check for working CXX compiler: C:/Programmation/Qt/Tools/mingw730_64/bin/g++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - found
-- Found Threads: TRUE
-- Boost version: 1.69.0
-- Found the following Boost libraries:
--   log
--   log_setup
--   thread
--   date_time
--   filesystem
--   regex
--   chrono
--   atomic
-- Boost Fichier en-têtes - C:/Boost/include/boost-1_69
-- Boost Fichiers objets - C:/Boost/lib
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/benbo/Downloads/Discographie

C:\Users\informaticienzero\Downloads\Discographie>mingw32-make
Scanning dependencies of target Discographie
[ 14%] Building CXX object CMakeFiles/Discographie.dir/discographie.cpp.obj
[ 28%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco.cpp.obj
[ 42%] Building CXX object CMakeFiles/Discographie.dir/donnees_disco_tests.cpp.obj
[ 57%] Building CXX object CMakeFiles/Discographie.dir/systeme_commandes.cpp.obj
[ 71%] Building CXX object CMakeFiles/Discographie.dir/utils.cpp.obj
[ 85%] Building CXX object CMakeFiles/Discographie.dir/main.cpp.obj
[100%] Linking CXX executable Discographie.exe
[100%] Built target Discographie


C:\Users\informaticienzero\Downloads\Discographie>Discographie.exe
[2019-03-26 17:12:07.500987] [0x00001d30] [info]    Lancement du projet Discographie.
> quitter
[2019-03-26 17:12:12.046525] [0x00001d30] [info]    Fin du programme.

Définir des variables au lancement

Typiquement, pour la partie MinGW, j’ai défini en dur la variable Boost_ARCHITECTURE comme valant "-x64". Mais si jamais on veut compiler en 32 bits ? Le mieux serait de ne pas avoir cette variable en dur, mais plutôt de la définir quand on en a besoin. C’est justement ce que nous permet de faire CMake.

cmake . -G "MinGW Makefiles" -DBoost_ARCHITECTURE="-x64"

L’option -DNOM permet de définir une variable NOM avec la valeur de notre choix. On peut ainsi préciser explicitement "-x64" quand on le veut, sans être forcé comme avant.

Le principe est le même pour les autres valeurs en dur, qui peuvent changer en fonction de l’environnement d’exécution, comme le chemin de Boost notamment. Je vous invite à définir ce genre de variable au lancement pour que n’importe quel utilisateur puisse personnaliser l’exécution.

Aller plus loin

CMake est un outil puissant, qui permet de gagner en souplesse, mais le maîtriser demande bien plus que de savoir les quelques commandes que nous avons vues ici. De nombreuses ressources sont disponibles, à commencer par le cours officiel sur le site de CMake. Vous pouvez également jeter un œil à ce tutoriel en français.

Par exemple, il est possible de lancer automatiquement Doxygen en même temps que la compilation, afin de disposer également de la documentation du projet. Vous pouvez aussi apprendre des techniques pour ne pas avoir à mettre à jour à la main la liste des fichiers d’en-têtes et sources. Mais tout ça, c’est de votre ressort maintenant. ;)

Aller plus loin

Si je devais vous présenter tous les outils utiles à un développeur C++, ce tutoriel serait deux fois plus gros minimum et ce chapitre bien indigeste. Nous en avons déjà vu trois, importants et très largement répandus. Mais il en existe encore de nombreux autres, que vous serez amenés à utiliser (ou pas) au fur et à mesure que vous progresserez.

TravisCI — De l’intégration continue

Imaginez qu’à chaque commit sur GitHub, votre code soit automatiquement compilé, les tests unitaires lancés et la documentation automatiquement générée et mise à jour ? C’est ce que permet de faire TravisCI et c’est ce qui s’appelle l’intégration continue. En plus, l’outil est gratuit si votre projet est open-source.

CppCheck — Vérification du code

Un autre outil qui rend de fiers services, j’ai nommé CppCheck. Cet outil effectue de nombreuses vérifications sur votre code pour vous aider à le rendre encore plus robuste. On peut citer notamment la vérification des limites de tableaux, les divisions par zéro, ou encore la vérification des exceptions lancées.

informaticienzero@DESKTOP-GGDRVV5:~/Documents/TutorielCpp-Discographie/Discographie$ cppcheck ./
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c ...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: MPRAS;_MPRAS...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: SCO_SV;_SCO_SV;sco_sv...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: SDCC;__SDCC_VERSION_MAJOR...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: SDCC;__SDCC_VERSION_MAJOR;__SDCC_VERSION_MAJOR...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: SIMULATE_VERSION_PATCH...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: SIMULATE_VERSION_PATCH;SIMULATE_VERSION_TWEAK...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: WIN32;_WIN32;__WIN32__...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: XENIX;_XENIX;__XENIX__...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: _AIX;__AIX;__AIX__;__aix;__aix__...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: _BEOS;__BEOS__;__BeOS...
Checking CMakeFiles/3.10.2/CompilerIdC/CMakeCCompilerId.c: _COMPILER_VERSION;_SGI_COMPILER_VERSION...
1/10 files checked 10% done
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp ...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: MPRAS;_MPRAS...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: SCO_SV;_SCO_SV;sco_sv...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: SIMULATE_VERSION_PATCH...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: SIMULATE_VERSION_PATCH;SIMULATE_VERSION_TWEAK...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: WIN32;_WIN32;__WIN32__...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: XENIX;_XENIX;__XENIX__...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: _AIX;__AIX;__AIX__;__aix;__aix__...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: _BEOS;__BEOS__;__BeOS...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: _COMPILER_VERSION;_SGI_COMPILER_VERSION...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: _COMPILER_VERSION;_SGI_COMPILER_VERSION;_SGI_COMPILER_VERSION...
Checking CMakeFiles/3.10.2/CompilerIdCXX/CMakeCXXCompilerId.cpp: _CRAYC...
2/10 files checked 20% done
Checking CMakeFiles/feature_tests.c ...
Checking CMakeFiles/feature_tests.c: __STDC_VERSION__...
3/10 files checked 30% done
Checking CMakeFiles/feature_tests.cxx ...
Checking CMakeFiles/feature_tests.cxx: __GXX_EXPERIMENTAL_CXX0X__...
4/10 files checked 40% done
Checking discographie.cpp ...
5/10 files checked 50% done
Checking donnees_disco.cpp ...
6/10 files checked 60% done
Checking donnees_disco_tests.cpp ...
7/10 files checked 70% done
Checking main.cpp ...
8/10 files checked 80% done
Checking systeme_commandes.cpp ...
9/10 files checked 90% done
Checking utils.cpp ...
10/10 files checked 100% done

Beaucoup d’informations, mais aucun problème trouvé sur le projet Discographie. Ouf ! :)

StackOverflow — La réponses à quasiment toutes les questions

S’il y a un site que tous les développeurs connaissent et lisent, c’est bien StackOverflow. C’est LE site de questions-réponses sur Internet. Si vous n’avez aucune réponse à votre problème sur StackOverflow, alors vous n’avez vraiment pas de chance du tout. Peu importe le langage, peu importe la technologie, tout est abordé sur ce site. Mettez-le dès maintenant en favori, il va vous sauver la vie !


En résumé

  • Le gestionnaire de code source git permet de sauvegarder et versionner son code source. Il permet ainsi de tracer un historique du projet, de revenir à des versions antérieures et de développer plusieurs fonctionnalités en parallèle.
  • Le service en ligne GitHub permet de partager son code source aux autres, permettant ainsi une sauvegarde pérenne, la création de bugs, la proposition de correctifs ou d’améliorations, entre autres choses.
  • CMake automatise la génération du code, permettant, avec un unique fichier de configuration, de générer des projets Visual Studio, des Makefiles et bien d’autres choses encore.
  • Chacun de ces outils offre de nombreuses possibilités que ce cours ne peut pas aborder et qu’il convient au lecteur de découvrir par lui-même.
  • De nombreux outils pour C++ sont disponibles, qu’un développeur découvre et utilise au fil du temps.