---
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: C++17
  language: C++17
  name: xcpp17
---

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "cbfcf0b3ffc220e808f50d1280312939", "grade": false, "grade_id": "cell-415f04d27b610548", "locked": true, "schema_version": 3, "solution": false, "task": false}}

# Semaine 10 : modularité, compilation séparée

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "f117371d70884a7bf3ba7d2cd02a4af7", "grade": false, "grade_id": "cell-6d952c4decd8c707", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## Objectifs pédagogiques

Cette semaine, comme la précédente, notre objectif est de gérer de
**« gros » programmes**, notamment pour continuer à vous préparer au
projet. Nous avions eu un premier aperçu du concept de **modularité**,
en découpant un programme en **fonctions**. Nous allons en rajouter
une couche en découpant un programme en plusieurs fichiers, grâce à la
**compilation séparée**. En prélude, nous discuterons le **cycle de
vie d'un programme**, notamment pour clarifier ce qu'est la
**compilation**.  Comme application nous utiliserons <!-- si les
conditions techniques à distance nous le permettent !-->la
**bibliothèque multimédia SFML** pour faire des dessins et des
interfaces graphiques. Cela pourra servir pour certaines parties
optionnelles du projet.

En TD et TP, nous mettrons d'abord en application la compilation
séparée, observant en détail un programme découpé en plusieurs
fichiers, puis reproduisant le schéma pour découper un autre programme
en plusieurs fichiers. Puis nous étudierons quelques exemples de
programmes utilisant la bibliothèque SFML et nous en inspirerons pour
programmer des dessins et interagir avec l'utilisateur.

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "66602a703f36c2f7e318dabbea427a84", "grade": false, "grade_id": "cell-6d952c4decd8c706", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## [Cours](cours.md)

- Cours : [Cycle de vie d'un programme](cours-cycle-de-vie-d-un-programme.md)
- Cours : [Modularité et compilation séparée](cours-modularite.md)
- Cours : [Digressions: surcharge, templates, espaces de noms](cours-digressions.md)
- Cours : [Conclusion](cours-conclusion.md)

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "1159f167ae813029628d5129a8ac8a3a", "grade": false, "grade_id": "cell-6d952c4decd8c705", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## [TD : compilation séparée, graphiques](TD.md)

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "a19c3f9a54cc2b0f7cb7ec988963186c", "grade": false, "grade_id": "cell-666b2425eb568c70", "locked": true, "schema_version": 3, "solution": false, "task": false}}

## TP

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "c14862eeb15c1d00c45129ecb04ba658", "grade": false, "grade_id": "cell-88edc2f254ba7294", "locked": true, "schema_version": 3, "solution": false}}

### Exercice 1 : préliminaires : compilation séparée

1.  Consultez le contenu des fichiers suivants : [factorielle.hpp](factorielle.hpp),
    [factorielle.cpp](factorielle.cpp), [factorielle-exemple.cpp](factorielle-exemple.cpp).

2.  Compilez le programme entier en suivant les instructions suivantes.
    Commencez par compiler chacun des bouts de programme (fichiers `.cpp`).
    Pour cela on utilise l'option `-c` :
    ```shell
    clang++ -c factorielle.cpp
    clang++ -c factorielle-exemple.cpp
    ```

    Ceci nous a créé deux fichiers, `factorielle.o` et
    `factorielle-exemple.o` qui sont des bouts de programme binaires.
    Vérifiez avec `ls` que ces fichiers ont bien été créés.

    Combinez ensuite (en anglais: *link* pour «édition de liens»)
    ces deux bouts de programme de la façon suivante :
    ```shell
    clang++ factorielle.o factorielle-exemple.o -o factorielle-exemple
    ```

    Vérifiez avec `ls` que cette commande crée bien un exécutable
    `factorielle-exemple`.

4.  Exécutez le programme `factorielle-exemple`.

5.  Consultez le fichier [factorielle-test.cpp](factorielle-test.cpp).
    Créez un exécutable `factorielle-test` en adaptant les étapes
    ci-dessus, puis testez ce nouveau programme.

6.  Une autre méthode pour compiler `factorielle-exemple` est de
    remplacer les trois commandes de la question (2) par la seule
    commande :
    ```shell
    clang++ factorielle.cpp factorielle-exemple.cpp -o factorielle-exemple
    ```

    Supprimez les fichiers `factorielle.o`, `factorielle-exemple.o` et
    `factorielle-exemple` de votre dossier avec `rm`. Testez alors la
    commande précédente. Quel(s) fichier(s) ont été créés ? En déduire
    les différences avec la méthode précédente. Selon le cas vous pourrez
    être amené à choisir l'une ou l'autre, notamment dans le projet.

+++ {"deletable": false, "nbgrader": {"cell_type": "markdown", "checksum": "59273bbf62585665b44663bfd10af06c", "grade": true, "grade_id": "cell-4234cd29242a210b", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false}}

% REMPLACEZ CETTE LIGNE PAR VOTRE RÉPONSE

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "08916a6087c9fab33a500eaeb42a3e19", "grade": false, "grade_id": "cell-41bec4fdd73fc56d", "locked": true, "schema_version": 3, "solution": false}}

### Exercice 2 : compilation séparée

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "0aa22e643a0731f21a052d645349ad26", "grade": false, "grade_id": "cell-89f33130471fc08e", "locked": true, "schema_version": 3, "solution": false}}

-   Ouvrez le fichier [fibonacci.cpp](fibonacci.cpp) et regardez son
    contenu. Remarquez que la fonction `main` mélange deux actions de
    nature très différente : d'une part lancer les tests de la
    fonction `fibonacci`, et d'autre part utiliser cette fonction pour
    interagir avec l'utilisateur. Ceci n'est pas très satisfaisant.

-   Réorganisez le fichier [fibonacci.cpp](fibonacci.cpp) en plusieurs
    fichiers en suivant le modèle de l'exercice précédent. Il y aura
    donc quatre fichiers :
	- [fibonacci.hpp](fibonacci.hpp),
    - [fibonacci.cpp](fibonacci.cpp),
    - [fibonacci-test.cpp](fibonacci-test.cpp),
    - [fibonacci-exemple.cpp](fibonacci-exemple.cpp).

    Faites attention à ne pas dupliquer de code.

+++ {"deletable": false, "nbgrader": {"cell_type": "markdown", "checksum": "a4f6c0ddadb36456443415b37c208e20", "grade": true, "grade_id": "cell-465531ee3287b0fd", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false}}

% REMPLACEZ CETTE LIGNE PAR VOTRE RÉPONSE

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "ed2c4d1d7c8b563e2a33580c914aa9d6", "grade": false, "grade_id": "cell-89f33130471fc08f", "locked": true, "schema_version": 3, "solution": false}}

-   Quels exécutables allez-vous construire? Pour chaque exécutable,
    quels fichiers allez-vous combiner pour l'obtenir ? Vérifiez
    pour chaque exécutable que chaque fonction utilisée (dont la
    fonction `main`) est définie une et une seule fois dans l'ensemble
    de fichiers correspondant.

+++ {"deletable": false, "nbgrader": {"cell_type": "markdown", "checksum": "281b7879783dc8e34eb42c3ff453b1d7", "grade": true, "grade_id": "cell-465531ee3287b0fe", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false}, "tags": []}

% REMPLACEZ CETTE LIGNE PAR VOTRE RÉPONSE

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "eb352fd592187fcac4ce19570c7bc952", "grade": false, "grade_id": "cell-89f33130471fc08g", "locked": true, "schema_version": 3, "solution": false}}

-   Compilez chacun des deux programmes (test et exemple) grâce à la
    compilation séparée, exécutez les et vérifiez que tout fonctionne
    correctement. En cas d'erreur, lisez le message d'erreur puis
    comparez attentivement vos fichiers et commandes avec ceux donnés
    pour la fonction `factorielle` (si vous avez la feuille de TD sous
    la main, l'énoncé de l'exercice 1 permet de visualiser facilement
    tous les fichiers pour factorielle).

    Notez ci-dessous les commandes utilisées pour la compilation :

+++ {"deletable": false, "nbgrader": {"cell_type": "markdown", "checksum": "1f1981e9323fd07e1e67885afb851325", "grade": true, "grade_id": "cell-465531ee3287b0ff", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false}}

% REMPLACEZ CETTE LIGNE PAR VOTRE RÉPONSE

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "36737f42fbf6300e344e76a3b1301b30", "grade": false, "grade_id": "cell-96bafcc3c30ace6e", "locked": true, "schema_version": 3, "solution": false}}

### Exercice 3 : Premiers graphiques avec Jupyter

1.  Refaites l'exercice 2 du [TD](TD.md) en complétant la feuille
    [premier-dessin](premier-dessin.md). Implantez chacun des items
    en vérifiant à chaque fois le résultat.

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "a57556751a58812ad6c4403b1ef85a5d", "grade": false, "grade_id": "cell-96bafcc3c30ace6f", "locked": true, "schema_version": 3, "solution": false}}

### Exercice 4 : Premiers graphiques avec SFML

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "f94f35a5a86a6a9bbfa70e9f2ec5274c", "grade": false, "grade_id": "cell-96bafcc3c30ace6g", "locked": true, "schema_version": 3, "solution": false}}

:::::{attention} SFML et sessions graphiques

Pour exécuter un programme utilisant la bibliothèque SFML, il est
nécessaire d'être dans une ***interface graphique***; sinon, vous
aurez une erreur comme :
```
./exemple-graphisme1 
Failed to open X11 display; make sure the DISPLAY environment variable is set correctly
```
(X11 est le gestionnaire de session graphique sous UNIX).

::::{admonition} Option 1 : Sur les ordinateurs des salles de TP

Vous êtes automatiquement dans une session graphique. Vous n'avez donc
rien de particulier à faire.

::::

::::{admonition} Option 2 : Avec le service JupyterHub@Paris-Saclay, depuis tout autre ordinateur ou tablette connectée à Internet
:class: dropdown

En parallèle de l'interface usuelle JupyterLab, vous pouvez lancer une
interface graphique (dite XFCE Desktop) sur le même serveur. Vous
pourrez ensuite basculer entre l'une et l'autre pour éditer et
compiler vos programmes d'une part, et les exécuter d'autre part.

<figure>

<video src="https://nicolas.thiery.name/Enseignement/Info111/media/screencast-sfml-on-jupyterhub.webm"
       width="95%" controls
       alt="Vidéo: lancer un programme graphique SFML avec JupyterHub"
       />

<figcaption>Vidéo : lancer un programme graphique SFML avec JupyterHub</figcaption>
</figure>

::::

::::{admonition} Sur votre machine personnelle
:class: dropdown

L'installation, la configuration et l'utilisation de la SFML peut être
un peu technique selon la configuration de votre ordinateur (système
d'exploitation, environnement de développement, ...).  Nous donnons
ici quelques pointeurs, mais après c'est à vous de fouiller la
documentation, notamment sur le [site de la
SFML](https://www.sfml-dev.org/index-fr.php) et de vous
débrouiller. Dans le doute, utilisez plutôt une des deux options
ci-dessus.

La section « Salle de TP virtuelle » sur la [page logiciels du site du
cours](https://nicolas.thiery.name/Enseignement/Info111/ComputerLab/README.html)
donne des instructions pour installer JupyterLab, compilateur C++ et
SFML. Sous GNU/Linux (Ubuntu, ...) cela devrait être suffisant pour
travailler.

Si vous souhaitez utiliser CodeBlocks, Visual Studio, ou tout autre
environnement de développement intégré (IDE), il faudra configurer cet
IDE pour utiliser la SFML. Plus encore que d'habitude, nous
recommandons de compiler en ligne de commande dans le terminal.

::::

:::::

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "a0ff90a81efe68e4975687391da8ddc6", "grade": false, "grade_id": "cell-96bafcc3c30ace6h", "locked": true, "schema_version": 3, "solution": false}}

1.  Ouvrez les fichiers [exemple-graphisme1.cpp](exemple-graphisme1.cpp)
    et [primitives.hpp](primitives.hpp) et consultez le premier.

2.  Compilez ce programme depuis le terminal avec
    (en une seule ligne !) :
    ```shell
    info-111 compile exemple-graphisme1.cpp primitives.cpp -o exemple-graphisme1 -lsfml-system -lsfml-window -lsfml-graphics
    ```

    Explication : le code binaire de SFML est réparti dans trois
    bibliothèques `sfml-system`, `sfml-window` et `sfml-graphics`.
    Les arguments `-lsfml-system`, ... indiquent au compilateur de les
    lier au programme (`-l` pour *link*).

3.  Lancez le programme obtenu avec :
    ```shell
    ./exemple-graphisme1
    ````
	Vous obtenez une fenêtre blanche, avec un (tout petit!) point
    rouge un peu à gauche, près du bord haut.

4.  Compilez le programme fourni
    [premier-dessin.cpp](premier-dessin.cpp)
    en adaptant la commande utilisée plus haut pour compiler
    [exemple-graphisme1.cpp](exemple-graphisme1.cpp).
    Complétez [premier-dessin.cpp](premier-dessin.cpp) à partir
    de la feuille [premier-dessin](premier-dessin.md). N'hésitez pas
    à changer la valeur de la variable `delai` pour voir le résultat
    s'afficher plus longtemps.

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "cb4372b6a345f17e803ae8856124785f", "grade": false, "grade_id": "cell-eaefcdbc75785adb", "locked": true, "schema_version": 3, "solution": false}}

### Exercice 5 : Souris et clavier ♣

1.  Pour vous donner une idée de l'utilisation de la SFML et
    de notre bibliothèque de primitives, lisez attentivement
    [primitives.hpp](primitives.hpp) et sa documentation.

2.  Consultez ensuite [exemple-graphisme2.cpp](exemple-graphisme2.cpp)
    et [exemple-graphisme3.cpp](exemple-graphisme3.cpp) pour en voir
    des exemples d'utilisation.

3.  Implantez l'exercice 4 du TD.

    <!-- Solutions dans le TD !-->

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "6bb1aa5b00f1758bbd44d55f54bc3ea6", "grade": false, "grade_id": "cell-5858dbcffa05aed3", "locked": true, "schema_version": 3, "solution": false}}

### Exercice 6 : Couche d'abstraction ♣

Pour vous approprier la couche d'abstraction, consultez son
implantation dans `primitives.cpp`. En vous inspirant de
ce qui est déjà fait, complétez l'implantation de la fonction
`draw_filled_rectangle` (documentée dans `primitives.hpp`).
Vous pouvez vous aider de la
[documentation en ligne de la SFML](https://www.sfml-dev.org/learn-fr.php).

+++ {"deletable": false, "nbgrader": {"cell_type": "markdown", "checksum": "61093ad3aeea2b37d7ce02c5c02d54cb", "grade": true, "grade_id": "cell-48f3d0b08106b27d", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false}}

% REMPLACEZ CETTE LIGNE PAR VOTRE RÉPONSE

+++ {"deletable": false, "editable": false, "nbgrader": {"cell_type": "markdown", "checksum": "d07cbe5dd5f6b305779f0b8a6d1128f3", "grade": false, "grade_id": "cell-48f3d0b08106b27e", "locked": true, "schema_version": 3, "solution": false, "task": false}}

### Exercice 7_: Jeu du Yams ♣

Reprenez le jeu du Yams du TP 6 en ajoutant une interface graphique.

On affichera les dés (soit avec du texte, soit avec des points) dans
la fenêtre. Revoyez [exemple-graphisme3.cpp](exemple-graphisme3.cpp)
pour des fonctions rapides. L'utilisateur pourra cliquer sur les dés
à combiner pour former une figure. (Utiliser par exemple `wait_mouse()`
pour cliquer sur les dés, et `wait_keyboard()` pour valider.) Le nombre
de points sera ensuite affiché.

À vous de concevoir les fonctions à introduire pour décomposer le
problème.