DEV Community

Pierre Gradot for Younup

Posted on • Originally published at younup.fr

Recompiler vos projets C et C++ plus rapidement avec ccache

ccache est un compiler cache, sous licence GPLv3. Il permet d'accélérer la recompilation de projets C et C++, mais aussi CUDA ou encore Objective-C et Objective-C++ (quelqu'un utilise encore ces 2 langages en 2022 ?). Il supporte les principaux compilateurs du marché: GCC, Clang, MSVC.

Fonctionnement

Comment ccache améliore le build d'un projet ? C'est en fait très simple. Quand vous compilez un fichier, il met le résultat en cache. Quand vous recompilez ce même fichier avec les mêmes options, il récupère directement le fichier objet du cache au lieu de le compiler vraiment.

Vous allez me dire :

Super, mais make ne recompile que les fichiers qui ont besoin de l'être, alors pourquoi ccache ferait mieux ?

Tout simplement parce make regarde l'état de votre projet et le compare au précédent build. Imaginez exécuter les commandes suivantes :

make
make clean
make
Enter fullscreen mode Exit fullscreen mode

Deux scénarios sont possibles lors de l'exécution de la dernière commande :

  1. Vous n'avez pas ccache, et make recompile tous les fichiers.
  2. Vous avez ccache, tous les fichiers objets sont récupérés du cache et le build est très rapide.

Le bonheur quand tu changes de branche

Vous allez me dire que vous faites rarement des make clean pour le plaisir. C'est vrai. Mais pensez à un scénario qui vous arrive souvent : le changement de branche avec Git (ou SVN, ou autre).

Imaginez un dossier dans lequel vous avez cloné votre dépôt Git. Vous êtes sur la branche master et vous avez compilé l'intégralité du projet. Vous faites un checkout d'une autre branche et vous travaillez sur cette branche. Une heure plus tard, vous revenez sur master.

Avec ccache, recompiler la branche master sera extrêmement rapide car tout est déjà dans le cache !

Le cache n'est pas limité à un dossier. Si vous avez plusieurs branches dans plusieurs dossiers, et que certains fichiers sont compilés de la même manière dans plusieurs branches, alors ccache vous fera aussi gagner du temps.

Mettre en place ccache sur son projet

Attention les yeux, ça va aller vite !

Vous téléchargez ccache, vous l'installez et vous l'ajouter au PATH.

Vous ajoutez les lignes suivantes à votre CMakeLists.txt :


find_program(CCACHE_PROGRAM ccache)

if (CCACHE_PROGRAM)
    message(NOTICE "ccache is enabled (found here: ${CCACHE_PROGRAM})")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "\"${CCACHE_PROGRAM}\"")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "\"${CCACHE_PROGRAM}\"")
else ()
    message(FATAL_ERROR "ccache has not been found")
endif ()
Enter fullscreen mode Exit fullscreen mode

Voilà, c'est tout !

Aucun effet visible ?

Vous avez activé ccache et vous ne voyez aucun effet. Ce n'est pas étonnant. Sur le site officiel, on peut lire :

The most important aspect of a compiler cache is to always produce exactly the same output that the real compiler would produce. [...] The only way you should be able to tell that you are using ccache is the speed.

Dans un usage normal, quand vous travaillez sur une branche particulière, vous ne verrez aucun effet. La différence est visible dans certaines situations, notamment quand vous changez de branche, quand on vous activez ou désactiver une option de compilation du projet, quand vous modifiez un header inclus dans de nombreux fichiers sources.

De plus, vous ne verrez pas de différence dans la liste de fichiers que CMake dit compiler ; vous verrez une différence sur le temps de build. En effet, CMake pense compiler la même chose, mais ccache intercepte les appels au compilateur et décide s'il doit réellement appeler le compilateur, ou s'il peut récupérer un fichier objet dans son cache et le renvoyer directement.

A titre d'exemple, j'ai fait la manipulation suivante sur le projet sur lequel je bosse quotidiennement en mission :

  1. Je me place dans le dossier où se trouve mon projet et donc mon CMakeLists.txt.
  2. Je nettoie le cache avec ccache --clear.
  3. Je m'assure de partir d'un projet remis à zéro avec cmake --build mon_dossier_de_build --target clean.
  4. Je builde mon projet avec cmake --build --preset=mon_preset (*). Lors de cette étape, ccache va mémoriser tous les résultats de compilation.
  5. Je cleane à nouveau mon projet.
  6. Je relance à nouveau une compilation. Cette fois, ccache peut utiliser son cache, créé 2 étapes plus haut, et ne recompiler aucun fichier.

Bilan : le premier build a duré 43 minutes ; le second a duré un peu moins de 4 minutes.

Splendide !

(*) = Si vous ne connaissez pas les CMake presets, je vous encourage à lire mon article sur le sujet, je suis sûr que vous allez aimer !

Conclusion

Je ne sais pas comment j'ai fait pour passer à côté de ccache pendant 11 ans, dont presque 6 ans d'utilisation quotidienne de C++. Je ne sais pas, vraiment...

Une chose est sûre : ça fait désormais partie de mon CMakeLists.txt template ! Comme je change souvent de branche ou que j'active puis désactive des options de debug, je vois souvent l'effet du cache. J'en suis au début de mon utilisation de ccache et je vais prochainement m'intéresser à la pertinence de le mettre en place sur Jenkins.

Je gagne beaucoup de temps en local grâce à ccache, et j'espère que vous en tirerez le même bénéfice !

Discussion (0)