Lorsque le volume de code devient trop important, même une division en multiples fonctions ne suffit plus à s'y retrouver. Il est donc souvent nécessaire de décomposer un projet en plusieurs fichiers source.
On utilise cette répartition pour mettre en avant la structure du projet. Par exemple, un fichier peut regrouper les fonctions qui concernent l'interface utilisateur, un autre les fonctions d'accès à une base de donnée, etc. Pour un projet d'envergure, les fichiers peuvent eux-même être groupés dans des sous-répertoires pour plus de clarté.
Si on se contente de répartir les fonctions dans plusieurs fichiers, pour compiler le projet il faudra donner la liste de tous les fichiers en argument.
bob@box:~$ gcc -ansi -pedantic -o projet modele.c vue.c controleur.c main.c
Cela pose deux problèmes. D'une part, la commande est longue à taper et donc source d'erreur. D'autre part, un projet de bonne taille devient très lent à compiler. Devoir attendre plusieurs minutes pour tester une modification de quelques lignes n'est pas une bonne façon de travailler.
Idéalement, on aimerait pouvoir compiler séparément chaque fichier source. On voit bien que ce ne sera pas possible si le fichier à compiler contient des appels à des fonctions définies dans d'autres fichiers. On dit alors que les fichiers sont dépendants les uns des autres.
On va limiter cette dépendance en créant une version «abrégée» de chaque source : un fichier d'en-tête. Celui-ci contiendra tout ce qui est nécessaire à la compilation des sources qui en dépendent (notamment les prototypes des fonctions), mais aucune instruction exécutable.
Chaque fichier peut maintenant être compilé individuellement. Comme il ne forme pas un programme complet, on n'obtient pas un exécutable mais seulement un fichier objet.
bob@box:~$ gcc -ansi -pedantic -c modele.c bob@box:~$ gcc -ansi -pedantic -c vue.c bob@box:~$ gcc -ansi -pedantic -c controleur.c bob@box:~$ gcc -ansi -pedantic -c main.c
Les fichiers objets ainsi obtenus peuvent être rassemblés par l'éditeur de lien pour former l'exécutable.
bob@box:~$ gcc -ansi -pedantic -o projet modele.o vue.o controleur.o main.o
Si on change un fichier source, son fichier objet doit être régénéré, mais les autres sont encore valables, ce qui fait gagner beaucoup de temps :
bob@box:~$ gcc -ansi -pedantic -c vue.c bob@box:~$ gcc -ansi -pedantic -o projet modele.o vue.o controleur.o main.o
Par contre, la commande qui crée l'exécutable est encore très longue. On a tout intérêt à automatiser cette étape, soit avec un script, soit avec l'outil make.