1. Utilisation de fonctions dans des fichiers séparés.
2. Utilisation de librairies.
- Un prototype indique au compilateur la signature d'une fonction.
- On met les prototypes des fonctions **publiques** dans des fichiers *headers*, extension `.h`.
- Les *implémentations* des fonctions vont dans des fichier `.c`.
# Prototypes de fonctions (3/3)
## Fichier header
- Porte l'extension `.h`
- Contient:
- définitions des types
- prototypes de fonctions
- macros
- directives préprocesseur (cf. plus loin)
- Utilisé pour décrire **l'interface** d'une librairie ou d'un module.
- Un fichier `C` (extension `.c`) utilise un header en *l'important* avec la directive `#include`{.C}:
```C
#include <stdio.h> // dans LD_LIBRARY_PATH
#include "chemin/du/prototypes.h" // explicite
```
# Génération d'un exécutable (1/5)
## Un seul fichier source
{width=100%}
# Génération d'un exécutable (2/5)
\footnotesize
```bash
gcc proc.c -o prog
```
1.**Précompilation: **`gcc` appelle `cpp`, le préprocesseur qui effectue de la substitution de texte (`#define`, `#include`, macros, ...) et génère le code `C` à compiler, portant l'extension `.i` (`prog.i`).
2.**Compilation assembleur: **`gcc` compile le code C en code assembleur, portant l'extension `.s` (`prog.s`).
3.**Compilation code objet: **`gcc` appelle `as`, l'assembleur, qui compile le code assembleur en code machine (code objet) portant l'extension `.o` (`prog.o`).
4.**Édition des liens: **`gcc` appelle `ld`, l'éditeur de liens, qui lie le code objet avec les librairies et d'autres codes objet pour produire l'exécutable final (`prog`).
Les différents codes intermédiaires sont effacés automatiquement.
# Génération d'un exécutable (3/5)
## Plusieurs fichiers sources
{width=100%}
# Génération d'un exécutable (4/5)
\footnotesize
::: Main
## `main.c`
```C
#include <stdio.h>
#include "sum.h"
int main() {
int tab[] = {1, 2, 3, 4};
printf("sum: %d\n", sum(tab, 4));
return 0;
}
```
:::
:::::::::::::: {.columns}
::: {.column width="45%"}
## `sum.h`
```C
#ifndef _SUM_H_
#define _SUM_H_
int sum(int tab[], int n);
#endif
```
:::
::: {.column width="55%"}
## `sum.c`
```C
#include "sum.h"
int sum(int tab[], int n) {
int s = 0;
for (int i = 0; i < n; i++) {
s += tab[i];
}
return s;
}
```
:::
::::::::::::::
# Génération d'un exécutable (5/5)
La compilation séparée se fait en plusieurs étapes.
## Compilation séparée
1. Générer séparément les fichiers `.o` avec l'option `-c`.
2. Éditer les liens avec l'option `-o` pour générer l'exécutable.
## Exemple
- Création des fichiers objets, `main.o` et `sum.o`
```bash
$ gcc -Wall -Wextra -std=c11 -c main.c
$ gcc -Wall -Wextra -std=c11 -c sum.c
```
- Édition des liens
```bash
$ gcc main.o sum.o -o prog
```
# Préprocesseur (1/2)
\footnotesize
## Généralités
- Première étape de la chaîne de compilation.
- Géré automatiquement par `gcc` ou `clang`.
- Lit et interprète certaines directives:
1. Les commentaires (`//`{.C} et `/* ... */`{.C}).
2. Les commandes commençant par `#`{.C}.
- Le préprocesseur ne compile rien, mais subtitue uniquement du texte.
## La directive `define`{.C}
- Permet de définir un symbole:
```C
#define PI 3.14159
#define _SUM_H_
```
- Permet de définir une macro.
```C
#define NOM_MACRO(arg1, arg2, ...) [code]
```
# Préprocesseur (2/2)
## La directive `include`{.C}
- Permet d'inclure un fichier.
- Le contenu du fichier est ajouté à l'endroit du `#include`{.C}.
- Inclusion de fichiers "globaux" ou "locaux"
```C
#include <file.h> // LD_LIBRARY_PATH
#include "other_file.h" // local path
```
- Inclusions multiples peuvent poser problème: définitions multiples. Les headers commencent par:
```C
#ifndef _VAR_
#define _VAR_
/* commentaires */
#endif
```
# Introduction à `make`
## A quoi ça sert?
- Automatiser le processus de conversion d'un type de fichier à un autre, en *gérant les dépendances*.
- Effectue la conversion des fichiers qui ont changé uniquement.
- Utilisé pour la compilation:
- Création du code objet à partir des sources.
- Création de l'exécutable à partir du code objet.
- Tout "gros" projet utilise `make` (pas uniquement en `C`).
# Utilisation de `make`
\footnotesize
Le programme `make` exécutera la série d'instruction se trouvant dans un `Makefile` (ou `makefile` ou `GNUmakefile`).
## Le `Makefile`
- Contient une liste de *règles* et *dépendances*.
- Règles et dépendances construisent des *cibles*.
- Ici utilisé pour compiler une série de fichiers sources
```
$ gcc -c example.c # + plein d'options..
$ gcc -o example exemple.o # + plein d'options
```
:::::::::::::: {.columns}
::: {.column width="55%"}
## `Makefile`
```bash
example: example.o
gcc -o example example.o
exmaple.o: exmaple.c example.h
gcc -c example.c
```
:::
::: {.column width="45%"}
## Terminal
```bash
$ make
gcc -c example.c
gcc -o example example.o
```
:::
::::::::::::::
# Syntaxe d'un `Makefile` (1/4)
{width=100%}