IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Gabriel Dos Reis propose une alternative simple à l'utilisation du préprocesseur C
Pour accéder à l'API d'une bibliothèque lors du CppCon 2015

Le , par Victor Vincent

5PARTAGES

4  0 
La plupart des logiciels est construit en utilisant un certain nombre de bibliothèques logicielles, soient des bibliothèques fournies par la plate-forme utilisée ou des bibliothèques internes intégrés au logiciel lui-même ou encore de bibliothèques tierces. Pour utiliser une bibliothèque, le développeur a besoin d’accéder à son API et à son implémentation. Dans la famille des langages C, l'interface d’une bibliothèque est accessible en incluant les fichiers d'en-tête appropriés comme suit : #include <ma_librairie.h>. Les modules fournissent une alternative plus simple pour utiliser les bibliothèques logicielles qui permet une meilleure gestion de la compilation et élimine bon nombre des problèmes inhérents à l'utilisation du préprocesseur C pour accéder à l'API d'une bibliothèque.

Pourquoi utiliser les modules ?

La réponse se trouve à plusieurs niveaux. Tout d’abord, il faut noter que le mécanisme utilisant #include est une très mauvaise façon de faire et ceci pour plusieurs raisons. La première est le fait qu’à chaque inclusion d’entête, le compilateur doit prétraiter cet entête et analyser son texte ainsi que chaque entête inclus dans ce dernier. Ce processus doit être répété partout où la même inclusion a été effectuée, ce qui implique une quantité de travail énorme et redondant. Une autre raison est liée au fait que les directives du type #include soient fragiles parce qu’elles sont traitées comme des inclusions textuelles par le préprocesseur et sont donc soumises aux directives de macro actives au moment de l’inclusion. Si une directive de macro entre en collision avec un nom de bibliothèque, cela peut provoquer des erreurs de compilation ou tout simplement casser l’API de la bibliothèque. Les programmeurs ont également adopté un certain nombre de conventions pour contourner les limites du préprocesseur C. Pour éviter les collisions par exemple, certains développeurs de librairies et de framework vont utiliser des noms d’entêtes précédés de (_) alors que ces derniers ne devraient pas être des macros.

Avantages des modules

Les modules permettent d'améliorer l'accès aux API des bibliothèques logicielles en remplaçant le modèle d'inclusion textuelle du préprocesseur avec un modèle sémantique, plus efficace et plus robuste. Du point de vue du développeur, le code ne change que légèrement, parce que c'est un import qui est utilisé à la place d'une directive #include du préprocesseur: import std.io. Cependant, l’importation de module est se comporte tout à fait différemment de la directive #include correspondante. Lorsque le compilateur voit une importation de module, il charge une représentation binaire du module et rend son API directement disponible pour l'application. Les directives du préprocesseur qui précèdent la déclaration d'importation n’ont aucune incidence sur l'API fournie, parce que le module lui-même a été compilé comme un module autonome. En outre, tous les flags de liaison nécessaires pour utiliser le module sont automatiquement fournis lors de l’importation du module. Ce modèle d'importation sémantique résout un grand nombre des problèmes du modèle d’inclusion du préprocesseur. Le temps de compilation est nettement optimisé car le module est compilé une seule fois et son importation est une opération à temps constant. L’API de chaque module est analysé une seule fois ce qui réduit le temps de compilation de NxM à N+M avec M, le nombre d’unités du programme et N le nombre d’entêtes inclus.Chaque module est analysé comme une entité autonome, avec donc un environnement préprocesseur cohérent. Le développeur n’a donc plus besoin d’utiliser des astuces ou conventions comme faire précéder ses noms d’en-têtes par (_). En outre quand un import est rencontré, les directives du préprocesseur sont ignorées. Une bibliothèque logicielle ne peut donc pas affecter la façon dont une autre est compilée, éliminant les dépendances quant à l’ordre d’importation des en-têtes.


Limites des modules

Les modules ne résolvent cependant pas tous les problèmes liés au modèle du préprocesseur. Il n’est pas possible d’éliminer complètement les en-têtes car il ne serait pas réaliste de vouloir faire faire des changements radicaux quant à la façon qu’ont les applications ou bibliothèques logicielles existantes d’utiliser des inclusions et les modules ont besoin d’interagir avec des bibliothèques existantes. Les modules ne prennent pas encore en compte la notion de versioning. Les développeurs devront donc faire avec les mécanismes de gestion de version existants. Contrairement à certains langages, les modules en C++ n’incluent aucune notion d’espaces de noms si bien qu’une structure déclarée dans un module sera toujours en conflit avec une autre structure du même nom déclarée dans un module différent.

Source : YouTube

Et vous ?

Que pensez vous de cette alternative à l'utilisation du préprocesseur C ?

Voir aussi

le forum Langage C++

la rubrique C++ (Cours, Tutoriels, FAQ, etc.)

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de JolyLoic
Rédacteur/Modérateur https://www.developpez.com
Le 15/10/2015 à 23:57
Pas certain d'avoir compris où tu voulais en venir...

La principale différence par rapport au .lib, c'est que ce binaire n'est pas vraiment un résultat de compilation, mais plus une réécriture de l'arbre des symboles. Il est donc auto-suffisant, contrairement au .lib. Et pour l'aspect compatibilité, rien n'est encore joué, ni dans un sens, ni dans l'autre. Après, vu la définition, je pense qu'il reste très peu à faire pour obtenir des fonctionnalités de chargement dynamique d'éléments définis dans un module.

Dans la proposition actuelle, un module peut comprendre plusieurs .cpp (et .h), mais un seul d'entre eux peut contenir l'interface du module, les autres ne peuvent en contenir que l'implémentation. C'est un point que j'aimerais creuser.

Je n'ai pas compris non plus dans la news cette histoire d'espace de nom... Il existe déjà et depuis fort longtemps la notion de namespace en C++, et elle est juste orthogonale à celle de module (comme en C#, mais pas comme en Java où les deux notions sont confondues). J'avoue avoir tendance à préférer ainsi.
3  0 
Avatar de foetus
Expert éminent sénior https://www.developpez.com
Le 14/10/2015 à 10:13
Donc en gros les modules cela correspond aux entêtes précompilées, à une compilation statique

Le mot-clef export avait quand même plus d'ambitions : faire des bibliothèques de templates, avec toutes les difficultés que cela amène.
2  0 
Avatar de kmedghaith
Membre confirmé https://www.developpez.com
Le 14/10/2015 à 9:35
Salut,

Merci pour l'article.
Juste une petite correction, il ne propose pas de remplacer préprocesseur par les imports, mais plutôt les includes par les imports.
Avec tout ce qu'a investit Qt et Boost dans les macros, sans parler des codes clients, je ne pense pas que le préprocesseur sera abandonné de sitôt.

MG
1  0 
Avatar de JolyLoic
Rédacteur/Modérateur https://www.developpez.com
Le 15/10/2015 à 9:43
Citation Envoyé par foetus Voir le message
Donc en gros les modules cela correspond aux entêtes précompilées, à une compilation statique
Qu'est-ce que tu entends par statique ici ?
Citation Envoyé par foetus Voir le message

Le mot-clef export avait quand même plus d'ambitions : faire des bibliothèques de templates, avec toutes les difficultés que cela amène.
Le seul problème d'export, c'est qu'il ne fonctionnait pas
(pour être plus précis, il n'apportait pas ce que certains avaient attendu de lui, en particulier, les améliorations de vitesse étaien réservés à des cas précis de compilation incrémentale , et il n'y avait aucune obscuration du code source)
1  0 
Avatar de foetus
Expert éminent sénior https://www.developpez.com
Le 15/10/2015 à 11:31
Citation Envoyé par JolyLoic Voir le message
Qu'est-ce que tu entends par statique ici ?
À l'instar des .lib, on va avoir pour chaque module du binaire "résultat de la compilation" [incompatible entre les compilateurs].

D'ailleurs je me demande, si pour 1 module ce sera exactement 1 couple .h/ .cpp [comme en Java], ou si on pourra avoir plusieurs couples .h/.cpp.

Et je dois être bête mais d'un côté on dit "Les programmeurs ont également adopté un certain nombre de conventions pour contourner les limites du préprocesseur C. Pour éviter les collisions" et de l'autre "les modules en C++ n’incluent aucune notion d’espaces de noms si bien qu’une structure déclarée dans un module sera toujours en conflit avec une autre structure du même nom déclarée dans un module différent"

1  0 
Avatar de renoo
Membre éprouvé https://www.developpez.com
Le 17/10/2015 à 13:15
L'un des problèmes avec ce système des modules est que cela peut avoir tendance à refermer l'environnement autour du compilateur.

Aujourd'hui je peux utiliser un analayseur de code pour verifier certaines choses, je peux utiliser une completion dans l'ide qui peux reparser les .hpp inclus. Ces outils sont parfois non liés au compilateur, comment cela se passerait il avec la solution des modules ? Est-ce que chaque outil doit stocker un resultat .lib quelque part ? Est-ce que ca ne doublonne pas la solution des headers pre-compilés ?
1  0 
Avatar de JolyLoic
Rédacteur/Modérateur https://www.developpez.com
Le 17/10/2015 à 14:04
Par rapport aux headers précompilés, c'est clair que les modules annoncent leur disparition, car ils devraient faire pareil en mieux !

Pour ce qui est des outils tiers, il faut effectivement qu'ils soient capables de lire le fichier de description des modules. Pour l'instant, le format proposé devrait être open-source, et j'espère qu'il y aura possibilité de définir un format standard, même si ce n'est pas gagné d'avance.

Par contre, en contrepartie, je sais que pour les outils, devoir lire des .h, c'est l'horreur :
  • C'est très compliqué (je le sais, je maintiens un tel outil...). Par contre, pour résoudre ça, il ne suffit pas que les modules existent, il faudrait aussi que l'usage des .h diminue jusqu'à ce qu'un outil puisse se permettre de les ignorer
  • C'est très long, les outils ayant les mêmes besoins que les compilateurs, mais ayant parfois des contraintes de temps plus strictes, liées à l'interactivité.
  • C'est très dépendant de la configuration (c'est actuellement ce point qui nous bloque le plus dans notre outil) : Que l'on dépende de la configuration primaire d'un projet pour avoir un outil sur ce projet est généralement acceptable. J'entends pas configuration primaire le fait de dire où se trouvent les bibliothèques utilisées par ce projet, et quelles macros définies sur la ligne de commande sont utilisées à l'intérieur du projet (probablement aucunes).
    Par contre, actuellement, on doit aussi définir la configuration totale, incluant aussi les chemins des bibliothèques utilisées par les bibliothèques, et les macros utilisées par celles-ci (et là, il y en a souvent plus, les bibliothèques tierce partie essayant de s'adapter à plein de situations).
    En pratique, aujourd'hui, on a une mauvaise configuration, sauf dans les cas où on est capable de lire les fichiers de l'outil de build du client, et donc, on donne des résultats incomplets.
0  0