Developpez.com

Plus de 2 000 forums
et jusqu'à 5 000 nouveaux messages par jour

C++ doit-il moderniser son mécanisme d'inclusion ?
CoderGears estime que c'est nécessaire pour qu'il devienne un langage vraiment moderne

Le , par Amine Horseman, Expert éminent sénior
Il y a 3 ans, les développeurs C++ avaient accueilli la nouvelle standardisation du langage avec beaucoup d'enthousiasme. Avec ce nouveau standard, plusieurs fonctionnalités avaient été ajoutées ou mises à jour pour faire du C++ un langage plus moderne et efficace, tout en conservant les anciens avantages tels que l'accès bas niveau à la mémoire par exemple.

Cependant, d'autres améliorations ont été reportées, car il aura fallu quand même 13 ans pour finir cette normalisation!
Une des améliorations possibles, qui restent toujours intéressantes, c'est de repenser le système d'inclusion de fichiers. C'est en tout cas ce que propose l’équipe CoderGears dans un billet de blog. Ils sont même allés plus loin en proclamant que « le C++ doit moderniser son mécanisme d’inclusion pour devenir vraiment un langage moderne ».

Jusqu'à présent, lorsqu'un fichier d'entête est inclus grâce à la directive #include, le préprocesseur analyse le contenu du fichier ainsi que tous les autres fichiers qu'il inclut lui-même. Et ceci est répété à chaque #include rencontré. Ce qui conduit parfois à un grand volume de travail redondant lorsque deux fichiers incluent la même bibliothèque, et que celle-ci n’est pas entourée de #ifndef et #endif. Mais ce n'est pas le seul problème, car lors de l’analyse, si une macro par exemple porte le même nom qu'un autre composant dans cette bibliothèque, c'est toute la compilation qui échoue. « Des problèmes se produisent dans des projets réels lorsque les entêtes pour deux bibliothèques différentes interagissent en raison de collisions macro, et les utilisateurs sont obligés de réorganiser les directives #include ou introduire des #undef pour briser le lien », explique CoderGears.

Certains programmeurs, avec le temps, ont développé de nouvelles habitudes pour éviter ça. Dans la documentation de Clang, on peut lire que « les programmeurs C++ ont adopté un certain nombre de conventions pour travailler autour de la fragilité du modèle de préprocesseur […] Les noms de macros sont écrits avec de LONG_PREFIXES_EN_MAJUSCULES pour éviter les collisions, et certains développeurs de bibliothèques utilisent même un double tiret dans les en-têtes pour éviter les collisions avec des noms "normaux"». Cette pratique, qui ne respecte pas les conventions du langage, est apparemment utilisée par certains pour contourner le problème.

Heureusement, une solution existe depuis la proposition de la norme C++ox, mais elle n'a pas été implémentée et a été retardée pour la norme C++11, puis renvoyée une nouvelle fois à une prochaine standardisation du langage de programmation.

Cette solution devrait alléger grandement le code des entêtes ainsi que leur traitement, puisqu'elle propose de ne plus inclure les fichiers d'une bibliothèque séparément. Par exemple : au lieu de charger les fichiers de la bibliothèque standard du C++ un à un, un simple import std suffira. L'entête gagnera donc beaucoup en clarté. De plus, cela inclura directement le fichier binaire de la bibliothèque (en tant que module déjà prêt), ce qui évitera au préprocesseur de le réanalyser à chaque fois, et évitera en même temps de tomber sur des conflits lors de la compilation.

« L’introduction de modules en C ++ ne sera pas une tâche facile », avoue l’équipe CoderGears. « Nous espérons que ce ne sera pas comme jisgaw (le système modulaire de Java) qui a été reportée de nombreuses années ».

Source : CoderGears Blog, Clang Documentation

Et vous?

Partagez-vous le point de vue de l’équipe de CoderGears ?


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de Lutarez Lutarez - Membre chevronné http://www.developpez.com
le 21/11/2014 à 17:16
Ce système d'inclusion préhistorique est certainement la principale raison qui m'a fait abandonné le C++ au profit du C#. Du coup, cela fait quelques années que j'attends de pieds fermes ces modules afin de m'y remettre un peu !
Avatar de Uther Uther - Expert éminent http://www.developpez.com
le 21/11/2014 à 18:17
Article bizarre qui enfonce des portes grandes ouvertes.

Toute personne qui a fait un minimum de C++ sait bien qu'on doit moderniser son mécanisme d'inclusion. Tout le monde le sait, tout le monde l'attend avec impatience a chaque nouvelle évolution du langage, mais on comprend également qu'un tel changement n'est pas anodin et qu'il prend du temps.
Avatar de Neckara Neckara - Expert éminent sénior http://www.developpez.com
le 21/11/2014 à 18:43
Bonjour,

Inclure directement le binaire de la bibliothèque.

Et on fait comment pour les macro, les templates ou les fonctions inlines .

Pourquoi ne pas tout simplement utiliser des fichiers d'en-têtes "pré-compilés" ?

lorsque deux fichiers incluent la même bibliothèque, et que celle-ci n’est pas entourée de #ifndef et #endif.

Je doute que ceci soit si fréquent que ça, et il existe aussi des solutions (pas géniales, mais qui existent).

Après il existe bien #pragma include_once qui ne fait pas parti de la norme mais, il me semble qu'il marche pas trop mal.

un simple import std suffira

Importer tout std ? Pour chaque fichier source utilisant la std ? Ceci me semble un peu lourd.
Importer uniquement les modules dont on a besoin ?
Code : Sélectionner tout
1
2
#import std.iostream 
#import std.vector
Je ne vois pas trop ce que ceci apporterait de plus que :
Code : Sélectionner tout
1
2
#include <iostream> 
#include <vector>
Je n'aime pas trop le système proposé, je pense qu'elle induit trop de changements sur les étapes de la chaîne de compilation.
Alors que je pense qu'on pourrait trouver des solutions plus simples et plus efficaces.
Avatar de Flob90 Flob90 - Membre expert http://www.developpez.com
le 21/11/2014 à 19:29
Bonjour,

Tout d'abord la proposition actuel : http://www.open-std.org/JTC1/SC22/WG...2014/n4214.pdf et la précédente : http://www.open-std.org/JTC1/SC22/WG...2012/n3347.pdf (je ne l'ai pas encore lu, donc je me base plus sur le premier).

@Neckara: Il n'est pas question de "binaire" en réalité, donc aucun problème pour fonctions inlines et templates. De plus dans l'idée, les modules ne doivent pas changer les règles actuelles.

Pour les import, ne t'inquiète pas, des sous-modules sont bien prévus, on ne va pas importer std en entier à chaque fois.

En effet le but est bien de changer en profondeur le système de compilation tout en permettant d'encore utiliser l'ancien. Le système actuel est basé sur du copier/coller, l'intérêt des modules c'est de dire : "voila, d'un côté les éléments suivants de cette unité sont importables par d'autre unité au sein de tel module, et de l'autre j'aimerais bien utilisé les éléments de tel module". On évite ainsi les copier/coller. Niveau implémentation, il faudrait regarder ce que clang avait proposé, mais je suppose que ça implique de générer des données supplémentaire (après le passage du préprocesseur) qui permet de savoir ce qu'il y a dans chaque module.

Niveau avantage, la limitation des violations de l'ODR (ie les erreurs "truc déjà définie") est celle qui m'attire le plus personnellement.
Avatar de Neckara Neckara - Expert éminent sénior http://www.developpez.com
le 21/11/2014 à 20:53
D'accord, donc on ne fait pas réellement "d'inclusion" (au sens copié/collé) et il n'est pas questions du fichier "binaire de la bibliothèques".

En lisant l'actualité, je comprenais "on prend le .so/.dll et on le 'copie-colle'"... Je ne dirais rien, mais j'en pense pas moins .

Si je comprend bien, à partir des fichiers .cpp, on va générer une sorte de "header précompilé" qui ne sera plus utilisée par le préprocesseur (pour copier/coller le code) mais après.

Par contre, est-ce qu'il est prévu que ces "header précompilé" soient distribuées à l'intérieur des .so/.dll ou ils pourront encore être distribués séparément ?

C'est une idée intéressante, à voir ce que cela donnera. Mais ce que j'attends avec plus d'impatience, c'est une normalisation de tout ce qui est "plugin" et chargement dynamique de bibliothèques dynamiques.
Avatar de Laurent7601 Laurent7601 - Provisoirement toléré http://www.developpez.com
le 21/11/2014 à 21:09
Mais ce que j'attends avec plus d'impatience, c'est une normalisation de tout ce qui est "plugin" et chargement dynamique de bibliothèques dynamiques.



Il existe divers façon de le faire pour linux, mac/osX et windows mais, en effet, ce n'est pas encore normalisé. :/

En attendant il faut faire sans, mais, je me demande si un jour il y aura une méthode standard.

PS : Les "include" pour le moment ça ne me gêne pas tellement, à part peut être, les problèmes dû à la double définition des macros cité plus haut.
Avatar de Neckara Neckara - Expert éminent sénior http://www.developpez.com
le 21/11/2014 à 21:16
Je pensais à quelque chose de plus orienté objet et sans casts de void * .
Quelque chose qui permettrait aussi d'utiliser les exceptions.

Une gestion de la mémoire pensée avec les plugins (pour ne pas faire planter les std::function/pointeurs intelligents), etc.
Avatar de Laurent7601 Laurent7601 - Provisoirement toléré http://www.developpez.com
le 21/11/2014 à 21:19
Oui c'est du C plutôt en effet (d'ou les extern "C") mais, je ne connais pas de manière pour le faire en c++. :/

Et j'en recherche une depuis, un bon bail déjà maintenant.

Les casts en void* c'est assez crade. :/

Petit message au chroniqueur d'actualité : si tu pouvais être un peu plus clair ça serait bien, merci.
Avatar de JolyLoic JolyLoic - Rédacteur/Modérateur http://www.developpez.com
le 21/11/2014 à 21:57
Citation Envoyé par Neckara  Voir le message
Mais ce que j'attends avec plus d'impatience, c'est une normalisation de tout ce qui est "plugin" et chargement dynamique de bibliothèques dynamiques.

Je n'ai pas vu beaucoup de discussions autour de ce sujet, probablement car :
- Ça demande énormément de travail de spécification difficile à écrire, en plus de la notion de modules (car la norme est aujourd'hui pudiquement silencieuse sur tout un tas de sujets qu'il faudrait expliciter pour définir ça)
- Il existe des pratiques un peu partout, mais qui sont divergentes sur tout un tas de points. Ce qui laisse présager des guerres de religion.

Je pense que le point de vue actuel est "attendons d'avoir les modules dans une version un peu près stable, et à ce moment là on regardera comment faire des modules chargés dynamiquement".

Citation Envoyé par Amine Horseman  Voir le message
Heureusement, une solution existe depuis la proposition de la norme C++ox, mais elle n'a pas été implémentée et a été retardée pour la norme C++11, puis renvoyée une nouvelle fois à une prochaine standardisation du langage de programmation.

C'est un peu optimiste comme vision... Il n'y a pas vraiment une solution dans la norme C++0x, juste une proposition d'évolution comme tant d'autres, qu'une personne a tenté d'implémenter pour Clang afin de la valider un peu. Ce qui est récent sur le sujet, c'est que d'autre compilateurs que Clang ont manifesté un intérêt pour le sujet (les dernières propositions sont de Microsoft), ce qui j'espère va fortement booster ce sujet qui était un peu au point mort après une première implémentation Clang.

Pour ce qui est du format de fichier, rien n'est précisé dans les dernières propositions. Ce sera probablement un format binaire (pour des raisons de performances), mais pas exécutable. Il n'est pas prévu d'imposer une compatibilité entre compilateurs sur ce format, même si on peut imaginer que des compilateurs se voulant compatibles (gcc et clang) vont avoir intérêt à se mettre d'accord pour un format commun.

On peut le voir comme un super PCH, qui apporterait une grande nouveauté par rapport aux PCH : La composabilité. Aujourd'hui, on fait un PCH pour un programme qui utilise libA et libB. Le but est de pouvoir faire un PCH pour libA, un autre pour libB, et de pouvoir dire qu'on utilise les deux pour notre programme.
Avatar de octal octal - Membre éclairé http://www.developpez.com
le 24/11/2014 à 12:36
la solution radicale au problème des includes a déjà été proposée à maintes reprise par Apple et ça n'a jamais été retenu (http://llvm.org/devmtg/2012-11/Gregor-Modules.pdf). Il s'agit de l'utilisation des "module". Le mécanisme date des années où un certain Monsieur Wirth a proposé le mécanisme de module dans Modula-2 puis Oberon. Il ne s'agit pas d'utiliser le binaire, il s'agit tout simplement de charger et analyser le module une seule fois, et d'avoir un référentiel de modules chargés. Chaque nouvelle inclusion ne fera que référencer le module en question (donc plus d'analyse redondante et plus de recompilation). Cela marche très bien pour Modula-2 et Oberon, mais l'organisme qui gère la standardisation du langage C++ est monopolisé par les intégristes tout aussi bornés les uns que les autres. On préfère rajouter des bizarreries comme la possiblité d'utiliser l'opérateur sizeof() sans les parenthèses quand il est appliqué à une variable, ce qui ne fait que rendre le langage encore plus m......que qu'autre chose, au lieu de reprendre les mécanismes des autres langages qui pourraient rendre le C++ bien plus clean et plus productif.
Offres d'emploi IT
Développeur symfony – (H/F)
Mobiskill - Ile de France - Paris (75000)
Consultant technique .net / sql h/f
INTEAM - Ile de France - Paris (75000)
Consultant Technico Fonctionnel Junior SAP H/F
Atos Technology Services - Rhône Alpes - Lyon

Voir plus d'offres Voir la carte des offres IT
Contacter le responsable de la rubrique Accueil