Skip to content
Snippets Groups Projects
cours-modularite.md 10.8 KiB
Newer Older
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
---
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: C++17
  language: C++17
  name: xcpp17
rise:
  auto_select: first
  autolaunch: false
  centered: false
  controls: false
  enable_chalkboard: true
  height: 100%
  margin: 0
  maxScale: 1
  minScale: 1
  scroll: true
  slideNumber: true
  start_slideshow_at: selected
  transition: none
  width: 90%
---

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

# Modularité, compilation séparée

Rappelez-vous notre **livre de recettes**. À l'époque, nous avons vu
comment **découper un programme en fonctions** pour plus de
**modularité**.  Cela permet de mieux le comprendre, petit bout par
petit bout, d'éviter les redites, etc.

Nous allons de même **découper un programme en plusieurs fichiers**.

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

## Compilation séparée

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

### Exemple

Considérons les trois programmes suivants :

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}, "tags": []}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

Dans Jupyter :

```{code-cell}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:tags: []
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
int monMax(int a, int b) {
    if ( a >= b )
        return a;
    else
        return b;
}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```

```{code-cell}
monMax(10, 1)
```

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}, "tags": []}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

[programme1.cpp](programme1.cpp) : maximum de deux entiers, avec un exemple

``` c++
#include <iostream>
using namespace std;

int monMax(int a, int b) {
    if ( a >= b )
        return a;
    else
        return b;
}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
int main() {
    cout << monMax(1, 3) << endl;
    return 0;
}
```

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}, "tags": []}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

[programme2.cpp](programme2.cpp) : maximum de deux entiers, avec interactivité

``` c++
#include <iostream>
using namespace std;

int monMax(int a, int b) {
    if ( a >= b )
        return a;
    else
        return b;
}

int main() {
    cout << "Entrez a et b:" << endl;
    int a, b;
    cin >> a >> b;
    cout << "Le maximum est: "
         << monMax(a, b) << endl;
    return 0;
}
```

+++ {"slideshow": {"slide_type": "slide"}}

On constate une **répétition** : les trois programmes définissent exactement
la même fonction `monMax`, qu'ils utilisent ensuite différemment.

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Pourrait-on **partager** la fonction `monMax` entre ces trois programmes ?
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

C'est ce que nous allons faire en définissant une mini-bibliothèque.
Voyons à quoi cela ressemble.

+++ {"slideshow": {"slide_type": "slide"}}

#### Exemple : une bibliothèque `max` simpliste

Contenu du fichier `max_simpliste.hpp` :
``` c++
/** La fonction max
 *  @param x, y deux entiers
 *  @return un entier,
 *  le maximum de x et de y
 **/
int monMax(int a, int b) {
    if ( a >= b )
        return a;
    else
        return b;
}
```

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Pour utiliser cette bibliothèque, il suffit de l'******inclure****** :
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

```{code-cell}
#include "max_simpliste.hpp"
```

```{code-cell}
monMax(1, 3)
```

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{attention}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
On appelle cela une bibliothèque en ******entêtes seuls****** (******header only******).
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

En `C++`, il y a des cas d'usage où cela peut être pertinent.

Il y a de sérieuses limitations à cette façon de structurer une bibliothèque.

Dans ce cours on évitera.
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

#### Exemple : une bibliothèque `max` dans les règles

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}

% TODO: ici et dans les pages suivantes: use literalinclude
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Contenu du fichier [max.hpp](max.hpp) :
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
/** La fonction max
 *  @param x, y deux entiers
 *  @return un entier,
 *  le maximum de x et de y
 **/
int monMax(int a, int b);
```

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Contenu du fichier [max.cpp](max.cpp) :
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
#include "max.hpp"

int monMax(int a, int b) {
    if ( a >= b )
        return a;
    else
        return b;
}
```

+++ {"slideshow": {"slide_type": "slide"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
#### Exemple : deux programmes utilisant la bibliothèque `max`
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Contenu du fichier [programme1.cpp](programme1.cpp):
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
#include <iostream>
using namespace std;
#include "max.hpp"

int main() {
    cout << monMax(1, 3) << endl;
    return 0;
}
```

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Contenu du fichier [programme2.cpp](programme2.cpp):
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
#include <iostream>
using namespace std;
#include "max.hpp"

int main() {
    cout << "Entrez a et b :" << endl;
    int a, b;
    cin >> a >> b;
    cout << "Le maximum est : "
         << monMax(a, b) << endl;
    return 0;
}
```

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

#### Exemple : les tests de la bibliothèque `max`

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Contenu du fichier [max-test.cpp](max-test.cpp) :
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
#include <iostream>
using namespace std;

#include "max.hpp"

/** Infrastructure minimale de test **/
#define CHECK(test) if (!(test)) cerr << "Test failed in file " << __FILE__ << " line " << __LINE__ << ": " #test << endl
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
void monMaxTest() {
    CHECK( monMax(2,3) == 3 );
    CHECK( monMax(5,2) == 5 );
    CHECK( monMax(1,1) == 1 );
}

int main() {
    monMaxTest();
}
```

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

### Qu'avons-nous vu ?

+++ {"slideshow": {"slide_type": "fragment"}}

#### Déclaration de fonctions

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Syntaxe
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
int monMax(int a, int b);
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Sémantique
-   Le programme ******définit****** quelque part une fonction `monMax` avec cette
    ******signature****** :   
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
    type des paramètres et type du résultat
-   Cette définition n'est pas forcément dans le même fichier
-   Si cette définition n'existe pas ou n'est pas unique, une erreur est
    déclenchée par le compilateur
-   Cette erreur est déclenchée au moment où l'on combine les différents
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
    fichiers : voir plus loin «Édition de liens»
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{hint} ♣ Application
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Deux fonctions qui s'appellent réciproquement
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

#### Compilation séparée (1)

-   Un programme peut être composé de plusieurs ***fichiers source***  
    Contenu :
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
    -   Des définitions de fonctions
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
    -   Des variables globales, ...

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}, "tags": []}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   Chaque fichier source est compilé en un ***fichier objet*** (extension : .o)  
    Contenu :
    -   Le code binaire des fonctions, ...

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}, "tags": []}

-   L'******éditeur de liens****** combine plusieurs fichiers objet en un
    ******fichier exécutable******
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "fragment"}}

Voyons cela pour un programme voulant utiliser la bibliothèque `max` :

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Les sources sont [max.cpp](max.cpp) et [programme.cpp](programme.cpp).

+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

On les compile séparément avec :

```shell
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
clang++ -c max.cpp
clang++ -c programme.cpp
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```

Cela produit les fichiers objets `max.o` et `programme.o`. Chacun est
un bout incomplet de programmes binaires : `max.o` contient le code
binaire de la fonction `max` mais pas la fonction `main`, et
réciproquement pour `programme.o`.

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Il ne reste plus qu'à combiner ces deux bouts de programmes binaires
pour obtenir un programme complet.

```shell
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
clang++ programme.o max.o -o programme
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Maintenant, on peut exécuter le programme obtenu autant de fois qu'on
le souhaite :

```shell
./programme
```

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

#### Compilation séparée (2)

**Au moment de l'édition de lien :**

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   Chaque fonction utilisée **doit être définie une et une seule fois**
-   La fonction `main` **doit être définie une et une seule fois**
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{hint} ♣ Quelques variantes autour des fichiers objets
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   Bibliothèques (.a) :
    Une archive contenant plusieurs fichiers objets .o
-   Bibliothèques dynamiques (.so) :
    Édition de lien dynamique au lancement du programme
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

#### Fichiers d'entête

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{prf:definition} Fichier d'entête
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Fichier `.hpp` (ou `.h` en C) contenant la *déclaration* des fonctions *définies* dans
le fichier `.cpp` correspondant
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{prf:example} Fichier d'entête `max.hpp`
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
int monMax(int a, int b);
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
#### Utilisation d'un fichier d'entête
:::{admonition} Syntaxe
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
#include "max.hpp"
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
:::{admonition} Sémantique
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
Utiliser la bibliothèque `max`
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{hint} Implantation en C++
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   Équivalent à copier-coller le contenu de `max.hpp` à l'emplacement du
    `#include "max.hpp"`
-   ♣ Géré par le préprocesseur (cpp)
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

#### Inclusion de fichiers d'entêtes standards

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Syntaxe
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
``` c++
#include <iostream>
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Sémantique
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   Charge la déclaration de toutes les fonctions définies dans la
    bibliothèque standard `iostream` de C++
-   Le fichier `iostream` est recherché dans les répertoires standards
    du système
-   Sous linux : `/usr/include`, ...
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "skip"}, "tags": []}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

## Résumé

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "slide"}, "tags": []}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

### Résumé : implantation d'une bibliothèque en C++

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Écrire un fichier d'entête (max.hpp)
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   La déclaration de toutes les fonctions publiques
-   *Avec leur documentation !*
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Écrire un fichier source (max.cpp)
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   La définition de toutes les fonctions
-   *Inclure le fichier .hpp !*
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
+++ {"slideshow": {"slide_type": "fragment"}}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Écrire un fichier de tests (maxTest.cpp)
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
-   Les fonctions de tests
-   Une fonction `main` lançant tous les tests
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "slide"}}

### Résumé : utilisation d'une bibliothèque en C++

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Inclusion des entêtes
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```c++
#include <iostream>   // fichier d'entête standard
#include "max.hpp"    // fichier d'entête perso
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} Compilation
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```shell
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
clang++ -c max.cpp
clang++ -c programme1.cpp
clang++ max.o programme1.o -o programme1
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

+++ {"slideshow": {"slide_type": "fragment"}}

Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::{admonition} En une seule étape
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```shell
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
clang++ max.cpp programme1.cpp -o programme1
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
```
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
:::

+++ {"slideshow": {"slide_type": "skip"}, "tags": []}
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed

## Suite

Après cette discussion des notions de modularité et de compilation
séparée, passons à quelques [digressions sur la surcharge,
les templates et les espaces de noms](cours-digressions.md).