Rappels Modularisation application C/C++

74
Modularisati on Applications C/C++ Bonnes pratiques

Transcript of Rappels Modularisation application C/C++

Page 1: Rappels Modularisation application C/C++

Modularisation Applications

C/C++Bonnes pratiques

Page 2: Rappels Modularisation application C/C++

“Parce que nous avons tous...

Page 3: Rappels Modularisation application C/C++

...rencontré ce type d’application….

Page 4: Rappels Modularisation application C/C++

...peiné à comprendre un code illi-si-ble..

Page 5: Rappels Modularisation application C/C++

...cru être maudits pour avoir à maintenir ce type d’applications

Page 6: Rappels Modularisation application C/C++

...pesé le pour et le contre avant la modification d’une ligne de code...

Page 7: Rappels Modularisation application C/C++

Développons notrearmure savoir/faire

et nos armes outils

pour chasser développer mieux.

Level max 99

Page 8: Rappels Modularisation application C/C++

Plan de la formation▧Objectifs▧Structure d’une application C/C++▧Exemples d’applications OpenSource▧Gestion des headers▧Gestion des includes▧Outillage

Page 9: Rappels Modularisation application C/C++

ObjectifsObjectifs primaires :

▧ Structurer un projet C/C++▧ Connaitre la différence entre include système et include▧ Connaître l’interaction entre le chemin des includes et les instructions

CMake▧ Savoir écrire un header C/C++ correct

Objectifs secondaires : ▧ Savoir exporter des définitions▧ Optimiser les dépendances entre les fichiers▧ Savoir pré-compiler des headers▧ Définir les bonnes pratiques de modularisation pour une application

C/C++

Page 10: Rappels Modularisation application C/C++

Que gagnons à modulariser nos applications ?

Page 11: Rappels Modularisation application C/C++

ModularisationLa programmation modulaire c’est l’art de concevoir une application logicielle qui met en oeuvre

la séparation des fonctionnalités d’un programmeen des modules indépendants, interchangeables et pour chaque module

que celui ne contienne uniquement ce qui est nécessaire à son exécution et sa fonctionnalité.

Page 12: Rappels Modularisation application C/C++

Vocabulaire

Technologie Paquetage Module

Java package *.jar

C++ namespace *.dll, *.so, *.a

C# namespace *.dll, NuGet

Page 13: Rappels Modularisation application C/C++

Comment modulariser notre application ?(Prendre un accent

Page 14: Rappels Modularisation application C/C++

La recette

1.Prendre les sources de l’application2.Récupérer les dépendances : Où ???3.Décomposer en module : Comment ??4.Construire les binaires5.Et après ? Intégration continue

Page 15: Rappels Modularisation application C/C++

Structure d’une

application C/C++

Page 16: Rappels Modularisation application C/C++

Que trouve-t-on dans une application codée en C/C+

+ ?

Page 17: Rappels Modularisation application C/C++
Page 18: Rappels Modularisation application C/C++

Bric à brac du codeur▧Scripts de compilation▧Ressources (images, fichiers de configuration)▧Documentation

ReadmeChangeLog

▧Sources▧Headers▧Bibliothèques▧...

Page 19: Rappels Modularisation application C/C++

Autopsie d’une application C/C++

Au niveau du source, un programme C/C++ est une collection de :

● Fichiers en-têtes (headers) (fichier .h ou .hpp)● Fichiers sources (fichier .c ou .cpp)

Page 20: Rappels Modularisation application C/C++

Contenu des fichiers en-têtesContenu partagé entre plusieurs fichiers sources :

▧types de données comme les structs ou les classes

▧les protypes de fonction ( déclarations)▧les constantes (les déclarations)▧les templates▧les types énumérés

Page 21: Rappels Modularisation application C/C++

La notion de dépendances entre fichiers

Tout fichier peut utiliser la directive #include afin insérer le contenu d’un autre fichierEx : Un fichier source peut inclure plusieurs fichiers en-têteEx : Un fichier en-tête peut inclure plusieurs fichiers en-tête

Page 22: Rappels Modularisation application C/C++

ExempleGame.cpp inclut Game.hGame.h inclut Item.h

Game.h et Item.h sont visibles dans Game.cpp Game.cpp

Game.h

Item.h

dépendances transitives

Page 23: Rappels Modularisation application C/C++

Dépendances circulaires

Parent.cpp

Parent.hpp Enfant.hpp

Enfant.cpp

Les fichiers Parent.hpp et Enfant.hpp dépendent l’un de l’autre

Page 24: Rappels Modularisation application C/C++

Solution pour corriger

Parent.cpp

Parent.hpp Enfant.hpp

Enfant.cpp

Les fichiers Parent.hpp et Enfant.hpp dépendent l’un de l’autre

Page 25: Rappels Modularisation application C/C++

Bien gérer ses dépendancesAccéler le temps de compilationLimiter le périmètre de régression / modificationFaciliter les futures évolutions de l’applicationAméliorer la compréhension de l’architecture global de l’application

Page 26: Rappels Modularisation application C/C++

Dépendances dans un vrai programme...

Page 27: Rappels Modularisation application C/C++

La décomposition

d’une application

C/C++

Page 28: Rappels Modularisation application C/C++

Exemples de projets C/C++

Page 29: Rappels Modularisation application C/C++

Projet NotePad++Projet

src

Composant 1

Composant 2

Fichiers .h

Fichiers .cpp

Fichiers .h

Fichiers .cpp

Fichiers .h

Fichiers .cpp

Page 30: Rappels Modularisation application C/C++

Projet WgetProjet

src

Fichiers .h

Fichiers .cpp

doc

po

Page 31: Rappels Modularisation application C/C++

Projet LibUProjet

srcs Fichiers .cpp

include

example

test

Fichiers .h

Fichiers .cpp

Fichiers .h

Fichiers .cpp

Fichiers .h

Page 32: Rappels Modularisation application C/C++

LibEvent https://github.com/libevent/libevent

Projet Fichiers .cpp

include

sample

test

Fichiers .h

Fichiers .cpp

Fichiers .h

Fichiers .cpp

Fichiers .h

Fichiers .h

Page 33: Rappels Modularisation application C/C++

Google FlagsProjet

doc

src

test

Fichiers .cpp

Fichiers .h

Fichiers .cpp

Fichiers .h

Page 34: Rappels Modularisation application C/C++

VorbisProjet

doc

lib

test

Fichiers .cpp

Fichiers .h

Fichiers .cpp

Fichiers .h

examples

Fichiers .cpp

Fichiers .h

include Fichiers .h

Page 35: Rappels Modularisation application C/C++

Structure proposée

Page 36: Rappels Modularisation application C/C++

Projet

srccpp

Fichiers .cpp

Fichiers .h

main

test

include

resources

cpp

resources

Fichiers .h

Fichiers .cpp

Fichiers .h

Structure projet classique

Page 37: Rappels Modularisation application C/C++

Mon Projet de Bibliothèque

Projet plus complexe

Bibliothèque

ExemplesExemple A

Exemple B

dépendances

Page 38: Rappels Modularisation application C/C++

Quel livrable souhaitez-vous ?

Page 39: Rappels Modularisation application C/C++

“Une archive pour la bibliothèque ?

les exemples sont dedans ou à coté ?

Page 40: Rappels Modularisation application C/C++

Une archive qui contient la bibliothèque et ses exemples-> Utilisation d’un CMake Global-> Les exemples réutilisent la bibliothèque via CMake-> La Compilation globale est réalisée via CMake

Situation A

Page 41: Rappels Modularisation application C/C++

Une archive pour la bibliothèque et une archive par exemple-> Utilisation d’un CMake pour la bibliothèque-> Utilisation d’un CMake par exemple-> Les exemples réutilisent la bibliothèque via le gestionnaire de dépendances-> La Compilation globale est réalisée via Gradle

Situation B

Page 42: Rappels Modularisation application C/C++

Digression...Quel outillage

pour le packaging ?

Page 43: Rappels Modularisation application C/C++
Page 44: Rappels Modularisation application C/C++
Page 45: Rappels Modularisation application C/C++
Page 46: Rappels Modularisation application C/C++
Page 47: Rappels Modularisation application C/C++

▧Utilisation de CMakePour la compilation multi-plateformePour l’utilisation dans Eclipse

▧Ajout de GradlePour gérer les dépendances inter-projetsPour construire le packaging et l’uploader

Solution Pragmatique

Page 48: Rappels Modularisation application C/C++

URL : https://github.com/Tocea/gradle-cpp-plugin/

Fonctionnalités de base :▧Gestionnaire de dépendances▧Construction du livrable

Fonctionnalités supplémentaires :▧Lancement Scripts de compilation▧Analyse statique de code

Rappel plugin Gradle

Page 49: Rappels Modularisation application C/C++

Travaux pratiques

Page 50: Rappels Modularisation application C/C++

Pendant ce temps...

Page 51: Rappels Modularisation application C/C++
Page 52: Rappels Modularisation application C/C++

Utilisez : ● la notion de buildType CMake● un autre sous-projet (et livrable)

Si vous avez besoin de recompiler un fichier ou une bibliothèque avec

des flags différents

Page 53: Rappels Modularisation application C/C++

Vérifiez● Que les projets ne soient pas

indépendants (release) et donc deux livrables différents

Utilisez : L’option OBJECT de CMake (http://www.cmake.org/pipermail/cmake-developers/2012-March/003693.html)

Si vous devez réutilisez des .obj entre deux sous-projets

Page 54: Rappels Modularisation application C/C++

Outillage pour gérer les dépendances

dump -H <program>

AIX

chatr <program>

HP-UX

ldd <program> Linux, SunOS5X$LIB_PATH AIX

$SHLIB_PATH

HP-UX

$LD_LIBRARY_PATH

Linux, SunOS5X

Page 55: Rappels Modularisation application C/C++

Outillage pour analyser les dépendancs

Visual StudioPC LintVisual LintEclipse IncludatorCLang Include what you use Include File DependencyJEtBrains IDE CLion

Page 56: Rappels Modularisation application C/C++

Précompilation d’entêtes (sous Unix +gcc)

stdafx.h:#include <string>#include <stdio.h>

a.cpp:#include "stdafx.h"int main(int argc, char**argv){ std::string s = "Hi"; return 0;}

Then compile as:> g++ -c stdafx.h -o stdafx.h.gch // Précompilation des headers> g++ a.cpp > ./a.out

Page 57: Rappels Modularisation application C/C++

Headers, includes et companie

Page 58: Rappels Modularisation application C/C++

Les Headers : mais pourquoi ?

http://webstory.my/

▧ Accélérer le temps de compilation

▧ Garder son code mieux organisé

▧ Séparer proprement les interfaces de l’implémentation

▧ Prérequis pour la développement de bibliothèques

Page 59: Rappels Modularisation application C/C++

▧ Compilation en deux temps :Chaque fichier est compilé avec l’ensemble de ses

headersL’ensemble des fichiers est assemblé (link) pour

construire le binaire final.▧ Les fichiers sources peuvent inclure des fichiers headers▧ Les fichiers headers peuvent inclure d’autres fichiers

headers

Comment cela fonctionne ?

Page 60: Rappels Modularisation application C/C++

Compilation et includes

Page 61: Rappels Modularisation application C/C++

Compilation et includes

Page 62: Rappels Modularisation application C/C++

// maclasse.hclass MaClasse{ void faitQuelquechose() { }};

Attention aux multiples inclusions

// main.cpp#include "maclasse.h" // définir MaClasse#include "maclasse.h" // Erreur de compilation - MaClasse already defined

Page 63: Rappels Modularisation application C/C++

#ifndef __MACLASSE_H_INCLUDED__ // si maclasse.h n’a pas encore été inclus#define __MACLASSE_H_INCLUDED__ // #define pour que le préprocesseur sache que cela a été inclus

// maclasse.hclass MaClasse{ void faireQuelquechose() { }};#endif

Attention aux multiples inclusions (solution)

Page 64: Rappels Modularisation application C/C++

▧ #include “filename”

Pour les headers maintenus par l’équipe / produit▧ #include <filename>

Pour les headers fournis par les bibliothèques standard (pré-définis)

Bibliothèques standard : (STL) + Packages installés sur la machine

▧ Sous GCC, la variable INCLUDE_PATH est exploitée pour retrouver les fichiers headers (argument -I)

Includes systèmes / includes

Page 65: Rappels Modularisation application C/C++

Les fichiers headers doivent être auto-suffisants

//=================================// include guard#ifndef __MYCLASS_H_INCLUDED__#define __MYCLASS_H_INCLUDED__

//=================================// forward declared dependenciesclass Foo;class Bar;

//=================================// included dependencies#include <vector>#include "parent.h"

//=================================// the actual classclass MyClass : public Parent // Parent object, so #include "parent.h"{public: std::vector<int> avector; // vector object, so #include <vector> Foo* foo; // Foo pointer, so forward declare Foo void Func(Bar& bar); // Bar reference, so forward declare Bar

};

#endif // __MYCLASS_H_INCLUDED__

Page 66: Rappels Modularisation application C/C++

N’incluez pas les dépendances transitives

// C.h#include “b.h”#include “a.h”

// C.cpp#include “c.h”#include “a.h” // USELESS

Page 67: Rappels Modularisation application C/C++

Positionnez l’include du source en premier

// C.cpp#include “c.hpp”

#include <iostream>...

Les fichiers headers doivent être autosuffisants.

Page 68: Rappels Modularisation application C/C++

▧ Incluez uniquement le header du module, jamais ses dépendances.

▧ Les fichiers headers ne doivent pas avoir d’instruction using::

▧ Le fichier header ne doit contenir que :Structure et déclarations de classesPrototypes de fonctionDéclaration de variables globales externes

▧ L’initialisation des variables doit être dans les fichiers sources

▧ Enlevez les déclarations internes (invisibles de l’utilisateur) et déplacez les dans les .cpp

Best practices Includes/Headers

Page 69: Rappels Modularisation application C/C++

▧ Incluez uniquement les fichiers nécessaires dans chaque header

▧ Chaque header doit avoir des gardes contre l’inclusion▧ Appliquez la règle : une structure, un fichier .h(pp) et un

fichier .c(pp)class MyClass => MyClass.hpp, MyClass.cpp

▧ Ne confondez pas #includes systèmes et #includes.▧ Utilisez les déclarations en avant (forward)▧ Attention aux fonctions inline▧ Bien gérer les déclarations externes et exportées

Best practices Includes/Headers

Page 70: Rappels Modularisation application C/C++

▧ Pas d’inclusion de fichiers .cpp▧ Déclarez les includes systèmes aussi dans les .cpp

Best practices Includes/Headers

Page 71: Rappels Modularisation application C/C++

// a.h#ifndef A_H#define A_H#include "b.h"

class A { B* b; };#endif A_H

Dépendances circulaires// b.h#ifndef B_H#define B_H#include "a.h"

class B { A* a; };#endif B_H

Page 72: Rappels Modularisation application C/C++

#include "a.h"

// start compiling a.h #include "b.h" // start compiling b.h #include "a.h" // compilation of a.h skipped because it's guarded

// resume compiling b.h class B { A* a }; // <--- ERROR, A is undeclared

Dépendances circulaires

Page 73: Rappels Modularisation application C/C++

Pour les longues nuits d’hiver▧ Modular programming : http://www.informit.com/articles/article.aspx?p=25003&seqNum=5▧ Detect Unnecessary includes (discussion) :

http://stackoverflow.com/questions/74326/how-should-i-detect-unnecessary-include-files-in-a-large-c-project

▧ Clang Include what you use : https://code.google.com/p/include-what-you-use/▧ Include File Dependency : http://www.mobile-mir.com/cpp/▧ JetBrains CLion : ▧ Include et headers : http://www.cplusplus.com/forum/articles/10627/▧ http://faculty.ycp.edu/~dhovemey/spring2011/cs320/lecture/lecture27.html

Page 74: Rappels Modularisation application C/C++

Vous pouvez me trouver :https://about.me/sylvain_leroy

Merci