Projet : étape 2 (semaine 3 du semestre)

Buts

Nous allons cette semaine commencer à utiliser la compilation séparée (eh oui, ça devait arriver !..).

Préliminaires :

Je vous rappelle qu'il est prévu une répartition des tâches du projet au sein du binôme. Je considère que chacun doit faire environ la moitié du travail lié au projet. Essayez donc de rapidement vous organiser, concevoir correctement la répartition et commencez à faire un Makefile (sujet du jour).

Par ailleurs, avant de vous lancer directement dans la réalisation de la nouvelle partie du projet, je vous conseille de vous assurer de bien avoir compris les concepts présentés en cours, par exemple en faisant au préalable quelques exercices si nécessaire.

Cette première partie du projet (de la semaine passée à la semaine prochaine) est assez progressive de sorte à vous permettre de vous organiser et prendre vos marques dans ce projet. Profitez-en donc pour faire les choses correctement dès le départ (cela permet de gagner du temps par la suite) et évitez absolument de prendre du retard... Je vous conseille d'avancer le plus possible en synchronisation avec le planning prévu, ou alors avec une semaine de décalage pour bien assimiler le cours, mais certainement pas plus.

Pour terminer avec les conseils et remarques préliminaires, n'oubliez pas de revenir de temps en temps consulter la page de description générale du projet et la page d'administration afin de situer votre travail courant par rapport au projet dans son ensemble.


[2*] Exercice P3 : Modularisation

Il est donc temps de se mettre à la compilation séparée... Voici un exercice censé vous aider à le faire.

Séparation

L'idée est d'avoir un fichier séparé pour chaque classe, plus un fichier pour le programme principal (et un/des fichier(s) pour les tests des classes).

Commençons donc avec la classe Vecteur3D.

Si vous ne l'avez pas encore séparé en trois fichiers, copiez le fichier Vecteur3D.cc en Vecteur3D.h. Et copiez-le encore une fois en testVecteur3D.cc. Vous avez donc maintenant trois fois le même fichier (même contenu) mais avec trois noms différents.
Évidemment, nous allons maintenant modifier chacun de ces fichiers séparément.

Dans le fichier testVecteur3D.cc :

  1. supprimez toutes les définitions de la classe Vecteur3D et de ses méthodes ;
  2. ne gardez que le main et les #include nécessaires  ici, c.-à-d. nécessaires à ce seul fichier ;
  3. ajoutez #include "Vecteur3D.h".

Dans le fichier Vecteur3D.h :

  1. ne gardez que la définition de la classe Vecteur3D ;
    supprimez aussi le #include <iostream> (sauf, comme évoqué plus haut, si vous l'utilisez dans ce fichier, ce qui ne devrait pas être le cas à ce stade, mais peut être avez vous déjà pris de l'avance sur le projet) et le using namespace (ça c'est obligatoire !) ;
    Comme expliqué en cours, IL NE DOIT JAMAIS Y AVOIR DE using namespace dans un fichier .h ! (malus)
  2. supprimez les définitions des méthodes (elles resteront dans le .cc)
    (Remarque avancée : sauf celles en 1 seule ligne, maximum, que vous pouvez garder ici, si jamais) ;
  3. ajoutez
    #pragma once
    
    en tout début de fichier ;
    ceci sert à éviter qu'un même fichier .h soit inclus par mégarde plusieurs fois dans une même compilation (ça arrive ... surtout quand votre projet va augmenter de taille !).

Dans le fichier Vecteur3D.cc :

  1. ne gardez que les définitions des méthodes ;
  2. « extériorisez » (hors de la classe) ces définitions en ajoutant Vecteur3D:: devant le nom de la méthode ;
  3. ajoutez #include "Vecteur3D.h" et supprimez tous les #include non strictement nécessaire à ce fichier ci.

Makefile

Créez maintenant le fichier Makefile permettant de construire (make) votre projet à partir de ses constituants.

Je vous donne ci-dessous un exemple simple, que vous pouvez télécharger en suivant ce lien, mais je vous recommande néanmoins d'aller voir le tutoriel sur les Makefile pour en savoir plus :

CXX = g++
CC  = $(CXX)

CXXFLAGS = -std=c++11  # C++11, ou autre suivant vos préférences

# Partie commentée : choisissez les options que vous voulez avoir
#                    en décommentant la/les lignes correspondantes
#
CXXFLAGS += -pedantic -Wall         # pour les purs et durs
# CXXFLAGS += -fsanitize=address    # pour analyse dynamique du code
# CXXFLAGS += -g                    # pour debugger
# CXXFLAGS += -O2                   # pour optimiser la vitesse

all: testVecteur3D

Vecteur3D.o: Vecteur3D.cc Vecteur3D.h

testVecteur3D.o: testVecteur3D.cc Vecteur3D.h

testVecteur3D: testVecteur3D.o Vecteur3D.o

Une fois tout ceci fait, tapez simplement make (dans un terminal se trouvant dans bon répertoire (~/myfiles/cpp/projet)) et...
..oh miracle ! Ça marche. (enfin j'espère pour vous !)
Vérifiez en lançant votre programme : ./testVecteur3D

CMake

Cette partie est totalement optionnelle. Elle est uniquement pour aller plus loin (plus « pro ») pour celles et ceux qui le souhaitent. Néanmoins, si vous envisagez de faire du graphisme, nous vous la conseillons. Si vous ne savez pas encore si vous allez vous lancer dans le graphisme ou non, vous avez le temps de revenir à cette section optionnelle lorsque vous passerez au graphisme. Elle est d'ailleurs également incluse dans le tutoriel du graphisme.

Maintenant que vous avez réussi à comprendre et implémenter la compilation séparée grâce à un Makefile (ce qui est, à mon avis, nécessaire pour vraiment comprendre), vous pouvez passer à un niveau supérieur, plus « pro » (mais moins pédagogique): CMake.

Comme évoqué dans l'exercice 2 de la série de la première semaine, vous pouvez reprendre cet exercice (exercice 2 de la semaine 1) avec CMake en suivant notre mini-tutoriel CMake.
Vous pouvez aussi simplement continuer ici, mais je voulais citer cet autre exemple pour rappel.

Pour commencer, organisons un peu plus les fichiers de votre projet. Je vous propose de séparer l'endroit où vous allez créer vos exécutables de l'endroit où vous stockez vos fichiers sources (.cc et .h). Je vous propose même de pouvoir organiser les différentes versions de votre projet (ou pour d'autres raisons) en différents sous-dossiers et d'avoir la structure suivante :

projet
├── build
└── version-1

Si vous souhaitez déjà anticiper la version graphique du projet, vous pouvez même aller plus loin et déjà créer un sous-dossier general dans version-1 : c'est que vous travaillerez (et sinon travaillez directement dans version-1; ce niveau de sous-dossier supplémentaire n'est pas important pour le moment).

Déplacez vos trois fichiers Vecteur3D.cc, Vecteur3D.h et testVecteur3D.cc dans version-1/general (ou dans version-1 si vous n'avez pas fait general).

Oubliez votre fichier Makefile (ou déplacez le dans un sous-dossier archives que nous ignorerons).

Créez un fichier CMakeLists.txt principal, directement dans le dossier projet et contenant :

# CMakeLists.txt général

cmake_minimum_required(VERSION 3.21)

project(NOM_DU_PROJET)

set(CMAKE_CXX_STANDARD 20)
set(PROJECT_WARNING_FLAGS
    -pedantic
    -Wall
    -Wextra
    -Wold-style-cast
    -Woverloaded-virtual
    -Wfloat-equal
    -Wshadow
    -Wwrite-strings
    -Wpointer-arith
    -Wcast-qual
    -Wcast-align
    -Wconversion
)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# Ajoutez ici tous les sous-dossiers contenant des fichiers sources
# que vous souhaitez voir compilés
add_subdirectory(version-1)

C'est ce fichier, CMakeLists.txt, qui dans CMake remplace le rôle du fichier Makefile. (En fait, c'est à partir de lui que CMake va créer des Makefile.)

Il faut ensuite simplement ajouter un fichier CMakeLists.txt dans chaque sous-dossier que l'on souhaite prendre en considération pour la création des exécutables finaux.

Par exemple, si vous avez créé un sous-répertoire general dans version-1/general (sinon ignorez simplement cette étape), il faut créer un fichier version-1/CMakeLists.txt qui contient simplement une seule ligne :

add_subdirectory(general)

Ensuite, dans version-1/general (ou dans version-1 si vous n'avez pas fait general), il faut créer le fichier CMakeLists.txt qui décrit quel exécutable nous souhaitons et comment le faire (c'est cette partie qui est l'équivalent de ce que vous aviez écrit dans votre Makefile) :

add_executable(testVecteur3D
  testVecteur3D.cc
  Vecteur3D.cc
)
target_compile_options(testVecteur3D PRIVATE ${PROJECT_WARNING_FLAGS})

Vous avez maintenant tout en place pour compiler. Si vous avez tout suivi depuis le début, vous avez l'architecture suivante (adaptez à vos choix) :

projet
├── archives
│   └── Makefile
├── build
├── CMakeLists.txt
└── version-1
    ├── CMakeLists.txt
    └── general
        ├── CMakeLists.txt
        ├── testVecteur3D.cc
        ├── Vecteur3D.cc
        └── Vecteur3D.h

Pour compiler, allez dans le sous-dossier build et lancez les deux commandes suivantes :

cmake ..
cmake --build .

Cela va créer tout ce qui est nécessaire pour compiler, puis lancer la compilation de votre programme, et créer l'exécutable bin/exemple1 (dans le sous-dossier build).

La commande « cmake .. » va générer les fichiers de construction pour le projet. Elle est à utiliser après chaque modification d'un CMakeLists.txt.

La commande « cmake --build . » va compiler tout le projet et créer les exécutables demandés. On peut compiler qu'un seul exécutable en ajoutant le nom de celui-ci à la fin de la commande, p.ex. :

cmake --build . --target nom_de_l_executable

L'intérêt d'être dans un sous-dossier build est de garder propres les sources du projet, en mettant tous les fichiers intermédaires (de construction et les exécutables) dans ce sous-dossier build.

Note : la plupart des éditeurs de code permettent aussi de définir des configurations pour faire ces constructions dans un autre dossier, et cela sans devoir passer par le terminal. Référez vous pour cela à la documentation de votre éditeur de code.

Et voilà ! Vous pouvez maintenant lancer votre programme : ./bin/testVecteur3D

Si ça vous intéresse, vous pouvez aller jeter un oeil aux fichiers Makefile que CMake a créés :


Dernière mise à jour le 12 février 2026
Last modified: Thu Feb 12, 2026