Pourquoi la compilation C++ prend-elle autant de temps?

compiler un fichier C++ prend beaucoup de temps par rapport à C# et Java. Il faut beaucoup plus de temps pour compiler un fichier C++ que pour exécuter un script Python de taille normale. J'utilise actuellement VC++ mais c'est la même chose avec n'importe quel compilateur. Pourquoi est-ce?

les deux raisons pour lesquelles je pouvais penser étaient le chargement des fichiers d'en-tête et l'exécution du préprocesseur, mais cela ne semble pas comme il devrait expliquer pourquoi il prend si longtemps.

460
demandé sur Martin Broadhurst 2008-11-25 21:25:14

14 réponses

plusieurs raisons

fichiers d'en-Tête

chaque unité de compilation nécessite des centaines, voire des milliers d'en-têtes pour être (1) chargée et (2) compilée. Chacun d'entre eux doit être recompilé pour chaque unité de compilation, parce que le préprocesseur garantit que le résultat de la compilation d'un en-tête pourrait varie entre chaque unité de compilation. (Une macro peut être définie dans une unité de compilation qui modifie la contenu de l'en-tête).

c'est probablement la raison principale , car il exige des quantités énormes de code à compiler pour chaque unité de compilation, et en outre, chaque en-tête doit être compilé plusieurs fois (une fois pour chaque unité de compilation qui inclut).

Linking

une fois compilés, tous les fichiers d'objets doivent être reliés entre eux. C'est fondamentalement un processus monolithique qui ne peuvent très bien être parallélisée, et de traiter l'ensemble de votre projet.

Analyse

la syntaxe est extrêmement compliquée à interpréter, dépend fortement du contexte, et est très difficile à désambiguer. Cela prend beaucoup de temps.

Modèles

dans C#, List<T> est le seul type qui est compilé, peu importe le nombre d'instanciations de liste que vous avez dans votre programme. En C++, vector<int> est un type complètement séparé de vector<float> , et chacun devra être compilé séparément.

ajoute que les modèles constituent un "sous-langage" complet que le compilateur doit interpréter, et cela peut devenir ridiculement compliqué. Même le code de métaprogrammation de template relativement simple peut définir des templates récursifs qui créent des douzaines et des douzaines d'instanciations de template. Les modèles peuvent également entraîner extrêmement complexe, avec ridiculement longue noms, en ajoutant beaucoup de travail supplémentaire pour l'éditeur de liens. (Il doit comparer beaucoup de noms de symboles, et si ces noms peuvent se développer en plusieurs milliers de caractères, cela peut devenir assez cher).

et bien sûr, ils exacerbent les problèmes avec les fichiers d'en-tête, parce que les modèles doivent généralement être définis dans les en-têtes, ce qui signifie beaucoup plus de code doit être analysé et compilé pour chaque unité de compilation. En code C simple, un en-tête Ne contient généralement que des déclarations forward, mais très peu de code réel. En C++, il est pas rare pour presque tout le code de résider dans les fichiers d'en-tête.

optimisation

C++ permet des optimisations très spectaculaires. C# ou Java ne permettent pas aux classes d'être complètement éliminées (ils doivent être là à des fins de réflexion), mais même un simple programme C++ peut facilement générer des dizaines ou des centaines de classes, Tous sont insérés et éliminés à nouveau dans la phase d'optimisation.

D'ailleurs, un c++ le programme doit être entièrement optimisé par le compilateur. Un programme C# peut compter sur le compilateur JIT pour effectuer des optimisations supplémentaires au moment de la charge, C++ n'a pas de telles "secondes chances". Ce que le compilateur génère est aussi optimisé que possible.

Machine

C++ est compilé en code machine ce qui peut être un peu plus compliqué que L'utilisation du bytecode Java ou .NET (surtout dans le cas de x86). (Ce qui est mentionné, de l'exhaustivité parce qu'il a été mentionné dans les commentaires, par exemple. En pratique, il est peu probable que cette étape prenne plus d'une infime fraction du temps total de compilation).

Conclusion

la plupart de ces facteurs sont partagés par le code C, qui compile en fait assez efficacement. L'étape d'analyse est beaucoup plus compliquée en C++, et peut prendre beaucoup plus de temps, mais le principal coupable est probablement les modèles. Ils sont utiles, et font de C++ un langage beaucoup plus puissant, mais ils prennent aussi leur tribut en termes de vitesse de compilation.

728
répondu jalf 2018-09-10 14:39:24

le ralentissement n'est pas nécessairement le même pour tous les compilateurs.

Je n'ai pas utilisé Delphi ou Kylix mais à L'époque de MS-DOS, un programme Turbo Pascal compilait presque instantanément, tandis que le programme équivalent Turbo C++ rampait.

les deux principales différences étaient un système de modules très puissant et une syntaxe qui permettait la compilation en un seul passage.

il est certainement possible que la vitesse de compilation juste cela n'a pas été une priorité pour les développeurs de compilateurs C++, mais il y a aussi des complications inhérentes à la syntaxe C/C++ qui la rendent plus difficile à traiter. (Je ne suis pas un expert en C, mais Walter Bright l'est, et après avoir construit divers compilateurs commerciaux C/C++, il a créé le langage D. l'un de ses changements était d'imposer une grammaire sans contexte pour rendre le langage plus facile à analyser.)

aussi, vous remarquerez que les Makefiles sont généralement configurés ainsi que chaque fichier est compilé séparément en C, donc si 10 fichiers source utilisent tous le même fichier include, ce fichier include est traité 10 fois.

36
répondu tangentstorm 2008-11-25 18:55:04

Parsing et génération de code sont en fait assez rapide. Le vrai problème est d'ouvrir et de fermer les dossiers. Rappelez-vous, même avec include guards, le compilateur ont toujours ouvert le .H de fichier, et de lire chaque ligne (et puis l'ignorer).

un ami une fois (pendant qu'il s'ennuyait au travail), a pris l'application de son entreprise et a mis tout -- tous les fichiers source et en-tête-- dans un grand dossier. Le temps de compilation est passé de 3 heures à 7 minutes.

32
répondu James Curran 2010-09-03 10:38:19

C++ est compilé en code machine. Si vous avez le pré-processeur, le compilateur, l'optimiseur, et enfin l'assembleur, qui ont à exécuter.

Java et C# sont compilés en byte-code / IL, et le Java virtual machine / .net Framework exécute (ou JIT compiler en code machine) avant l'exécution.

Python est un langage interprété qui est aussi compilé en byte-code.

je suis sûr qu'il y a d'autres raisons pour cela aussi, mais en général, ne pas avoir à compiler dans le langage machine natif permet de gagner du temps.

16
répondu Alan 2010-09-02 16:06:51

une autre raison est l'utilisation du préprocesseur C pour localiser les déclarations. Même avec header guards .h doit encore être analysé encore et encore, chaque fois qu'ils sont inclus. Certains compilateurs prennent en charge des en-têtes pré-compilés qui peuvent aider avec cela, mais ils ne sont pas toujours utilisés.

Voir aussi: C++ Frequently Questionned Answers

15
répondu Dave Ray 2008-11-25 18:32:37

les enjeux Les plus importants sont:

1) L'infini d'en-tête de ré. Déjà mentionné. Les mesures d'atténuation (comme #pragma une fois) ne fonctionnent habituellement que par unité de compilation et non par construction.

2) le fait que la chaîne d'outils est souvent séparée en plusieurs binaires (marque, préprocesseur, compilateur, assembleur, archiveur, impdef, linker, et dlltool dans les cas extrêmes) que tous doivent réinitialiser et recharger tous les états tout le temps pour chaque invocation (compilateur, assembleur) ou chaque couple de dossiers (archiveur, linker, et dlltool).

Voir aussi cette discussion sur comp.compilateurs: http://compilers.iecc.com/comparch/article/03-11-078 spécialement celui-ci:

http://compilers.iecc.com/comparch/article/02-07-128

notez que John, le modérateur de comp.les compilateurs semble d'accord, et que cela signifie qu'il doit être possible d'obtenir le même vitesses pour C aussi, si on intègre complètement la chaîne d'outils et met en œuvre des en-têtes précompilés. De nombreux compilateurs C commerciaux le font dans une certaine mesure.

notez que le modèle Unix qui consiste à tout intégrer dans un binaire séparé est une sorte de modèle du pire cas Pour Windows (avec sa lente création de processus). Il est très visible lorsque L'on compare les temps de construction de GCC entre Windows et *nix, surtout si le système make/configure appelle aussi certains programmes juste pour obtenir des informations.

11
répondu Marco van de Voort 2016-07-03 17:28:25

Bâtiment C/C++: ce qui se passe vraiment et pourquoi est-il si long

une part relativement importante du temps de développement d'un logiciel n'est pas consacrée à l'écriture, à l'exécution, au débogage ou même à la conception de code, mais à l'attente de terminer la compilation. Pour accélérer les choses, nous devons d'abord comprendre ce qui se passe lorsque le logiciel c/c++ est compilé. Les étapes sont à peu près les suivantes:

  • Configuration
  • Construire l'outil de démarrage
  • contrôle de dépendance
  • Compilation
  • Linking

Nous allons maintenant examiner chaque étape plus en détail en se concentrant sur la façon dont ils peuvent être réalisés plus rapidement.

Configuration

C'est la première étape pour commencer à construire. Habituellement signifie exécuter un configure script ou CMake, Gyp, SCons ou un autre outil. Cela peut prendre n'importe quoi d'une seconde à plusieurs minutes pour des scripts de configuration très grands basés sur des Autotools.

cette étape se produit relativement rarement. Il ne doit être exécuté qu'en cas de changement de configuration ou de modification de la configuration de construction. À moins de changer les systèmes de construction, il n'y a pas grand chose à faire pour accélérer cette étape.

création D'outils de construction

C'est ce qui arrive lorsque vous courez ou cliquez sur l'icône sur un IDE (qui est généralement un alias pour le faire). L'outil de compilation démarre et lit ses fichiers de configuration ainsi que la configuration de compilation, qui sont généralement la même chose.

selon la complexité et la taille de la construction, cela peut prendre une fraction de seconde à plusieurs secondes. En soi ce ne serait pas si mal. Malheureusement, la plupart des systèmes de construction basés sur des marques provoquent des tens invocables. à des centaines de fois pour chaque construction. Habituellement, cela est causé par l'utilisation récursive de faire (ce qui est mauvais).

il est à noter que la raison pour laquelle Make est si lent n'est pas un bogue d'implémentation. La syntaxe des Makefiles a quelques bizarreries qui rendent une implémentation vraiment rapide presque impossible. Ce problème est encore plus perceptible lorsqu'il est associé à l'étape suivante.

contrôle de dépendance

une fois le l'outil de compilation a lu sa configuration, il doit déterminer quels fichiers ont changé et lesquels doivent être recompilés. Les fichiers de configuration contiennent un graphique acyclique direct décrivant les dépendances de construction. Ce graphique est habituellement construit pendant l'étape de configuration. Le temps de démarrage de l'outil de compilation et le scanner de dépendances sont exécutés à chaque Compilation. Leur exécution combinée détermine la limite inférieure du cycle edit-compile-debug. Pour les petits projets, ce temps est généralement de quelques secondes. Ce est tolérable. Il y a des alternatives à faire. Le plus rapide D'entre eux est Ninja, qui a été construit par les ingénieurs de Google pour le chrome. Si vous utilisez CMake ou Gyp pour construire, il suffit de passer à leur Ninja backends. Vous n'avez pas à changer quoi que ce soit dans les fichiers de construction eux-mêmes, il suffit de profiter de la vitesse boost. Ninja n'est pas emballé sur la plupart des distributions, cependant, de sorte que vous pourriez avoir à l'installer vous-même.

Compilation

à ce point nous invoquons enfin le compilateur. Voici les étapes approximatives qui ont été franchies.

  • comprend la fusion
  • Analyse du code
  • génération de Code / optimisation

contrairement à la croyance populaire, compiler C++ n'est pas vraiment si lent. Le STL est lent et la plupart des outils de compilation utilisés pour compiler C++ sont lents. Cependant, il existe des outils plus rapides et des moyens d'atténuer les parties lentes de la langue.

les utiliser prend un peu d'huile de coude, mais les avantages sont indéniables. Des temps de construction plus rapides conduisent à des développeurs plus heureux, plus d'agilité et, finalement, un meilleur code.

9
répondu Ravindra Acharya 2015-10-15 10:48:35

un langage compilé va toujours exiger un plus grand overhead initial qu'un langage interprété. De plus, peut-être que vous n'avez pas très bien structuré votre code C++. Par exemple:

#include "BigClass.h"

class SmallClass
{
   BigClass m_bigClass;
}

compile beaucoup plus lent que:

class BigClass;

class SmallClass
{
   BigClass* m_bigClass;
}
7
répondu Andy Brice 2008-11-25 18:33:53

Un moyen facile de réduire le temps de compilation dans les grands projets C++ est de faire un *.cpp incluez le fichier qui inclut tous les fichiers cpp de votre projet et compilez-le. Cela réduit le problème d'explosion de l'en-tête à une seule fois. L'avantage est que les erreurs de compilation référencent toujours le bon fichier.

par exemple, supposons que vous avez a.cpp, b.cpp et c.cpp.. créer un fichier: de tout.cpp:

#include "a.cpp"
#include "b.cpp"
#include "c.cpp"

puis compiler le projet par juste faire tout.cpp

5
répondu rileyberton 2013-03-03 22:35:22

Certaines raisons sont:

1) la grammaire c++ est plus complexe que C# ou Java et prend plus de temps à analyser.

2) (plus important) le compilateur C++ produit du code machine et réalise toutes les optimisations pendant la compilation. C# et Java vont juste à mi-chemin et laisser ces étapes à JIT.

4
répondu Nemanja Trifunovic 2008-11-25 18:27:36

le compromis que vous obtenez est que le programme fonctionne un peu plus vite. Ce peut être un confort froid pour vous pendant le développement, mais il pourrait compter beaucoup une fois le développement est terminé, et le programme est juste dirigé par les utilisateurs.

4
répondu T.E.D. 2008-12-31 15:08:32

la plupart des réponses sont un peu imprécises en mentionnant que C# s'exécute toujours plus lentement en raison du coût d'exécution des actions qui en C++ ne sont effectuées qu'une seule fois au moment de la compilation, ce coût de performance est également affecté par les dépendances d'exécution (plus de choses à charger pour pouvoir s'exécuter), sans mentionner que les programmes C# auront toujours une empreinte mémoire plus élevée, ce qui fait que les performances sont plus étroitement liées à la capacité du matériel disponible. Le même est vrai pour d'autres langues qui sont interprétées ou dépendent d'une VM.

2
répondu Panic 2009-06-20 05:10:56

il y a deux problèmes que je peux imaginer qui pourraient affecter la vitesse à laquelle vos programmes en C++ compilent.

possible ISSUE #1 - compiler l'en-tête: (cela peut ou non avoir déjà été abordé par une autre réponse ou commentaire.) Microsoft Visual C++ (A. K. A. VC++) supporte les en-têtes précompilés, ce que je recommande fortement. Lorsque vous créez un nouveau projet et sélectionnez le type de programme que vous créez, une fenêtre Setup wizard devrait apparaître sur votre écran. Si vous appuyez sur le bouton "Suivant >" au bas de la fenêtre, vous accéderez à une page qui contient plusieurs listes de fonctionnalités; assurez-vous que la case à côté de l'option "en-tête précompilé" est cochée. (NOTE: cela a été mon expérience avec les applications de console Win32 En C++, mais ce n'est peut-être pas le cas avec tous les types de programmes en C++.)

numéro POSSIBLE #2 - L'emplacement étant compilé à: cet été, j'ai pris un nous avons dû stocker tous nos projets sur des lecteurs flash de 8 Go, car les ordinateurs du labo que nous utilisions étaient effacés tous les soirs à minuit, ce qui aurait effacé tout notre travail. Si vous compilez à un périphérique de stockage externe pour des raisons de portabilité/sécurité/etc., il peut prendre un très long temps (même avec les en-têtes précompilés que j'ai mentionnés ci-dessus) pour votre programme à compiler, surtout si c'est un programme assez grand. Mon conseil pour vous dans ce cas serait de créer et compiler des programmes sur le disque dur de l'ordinateur que vous utilisez, et chaque fois que vous voulez/besoin d'arrêter de travailler sur votre(s) projet (s) pour une raison quelconque, transférez-les à votre périphérique de stockage externe, puis cliquez sur l'icône "en toute sécurité supprimer le matériel et éjecter les médias", qui devrait apparaître comme un petit lecteur flash derrière un petit cercle vert avec un crochet blanc sur elle, pour déconnecter.

j'espère que cela vous aidera; faites-moi savoir si c'est le cas! :)

1
répondu cjor530 2016-08-18 02:11:17

comme déjà commenté, le compilateur passe beaucoup de temps instantiating et instantiating over again the templates. À tel point qu'il y a des projets qui se concentrent sur ce point particulier, et réclament une vitesse de 30x observable dans certains cas vraiment favorables. Voir http://www.zapcc.com .

0
répondu akim 2015-05-26 10:36:07