Bien que je puisse coder, je n'ai pas encore d'expérience dans le travail sur de grands projets. Ce que j'ai fait jusqu'à présent était soit de coder de petits programmes qui se compilaient en quelques secondes (divers exercices c / c ++ comme des algorithmes, des principes de programmation, des idées, des paradigmes, ou simplement d'essayer des API ...) ou de travailler sur des projets plus petits qui étaient fait dans un ou des langages de script (python, php, js) où aucune compilation n'est nécessaire.
Le truc, c'est que lorsque je code dans un langage de script, chaque fois que je veux essayer si quelque chose fonctionne - je lance simplement le script et vois ce qui se passe. Si les choses ne fonctionnent pas, je peux simplement changer le code et l'essayer à nouveau en exécutant le script à nouveau et continuer à le faire jusqu'à ce que j'obtienne le résultat que je voulais. Mon point est que vous n'avez pas à attendre rien à compiler et à cause de cela, il est assez facile de prendre une grande base de code, de la modifier, d'y ajouter quelque chose ou de simplement jouer avec - vous pouvez voir les changements instantanément.
Comme exemple, je prendrai Wordpress. Il est assez facile d'essayer de comprendre comment créer un plugin pour cela. D'abord, vous commencez par créer un simple plugin "Hello World", puis vous créez une interface simple pour le panneau d'administration pour vous familiariser avec l'API, puis vous le construisez et faites quelque chose de plus complexe, en attendant de changer l'apparence de quelques fois .. L'idée d'avoir à recompiler quelque chose d'aussi gros que WP maintes et maintes fois, après chaque modification mineure pour essayer "si cela fonctionne" et "comment cela fonctionne / se sent" semble juste inefficace, lente et erronée.
Maintenant, comment pourrais-je faire cela avec un projet écrit dans un langage compilé? Je voudrais contribuer à certains projets open-source et cette question continue de me déranger. La situation diffère probablement d'un projet à l'autre où certains d'entre eux qui ont été pensés au préalable avec sagesse seront d'une certaine manière "modulaires" tandis que d'autres ne seront qu'une grosse goutte qui doit être recompilée encore et encore.
J'aimerais en savoir plus sur la façon dont cela se fait correctement. Quelles sont les pratiques, approches et conceptions de projets (modèles?) Communes pour y faire face? Comment appelle-t-on cette "modularité" dans le monde des programmeurs et à quoi dois-je google pour en savoir plus? Est-ce souvent que les projets sortent de leurs proportions de première pensée qui deviennent gênantes après un certain temps? Existe-t-il un moyen d'éviter une longue compilation de projets pas si bien conçus? Un moyen de les modulariser d'une manière ou d'une autre (peut-être en excluant des parties non vitales du programme pendant le développement (d'autres idées?))?
Merci.
la source
Réponses:
Tout comme cela a été dit, vous ne recompilez jamais l'intégralité du projet chaque fois que vous effectuez une petite modification. Au lieu de cela, vous recompilez uniquement la partie du code qui a changé, ainsi que tout le code qui en dépend.
En C / C ++, la compilation est assez simple. Vous compilez la traduction de chaque fichier source en code machine (nous les appelons des fichiers objets * .o), puis vous liez tous vos fichiers objets en un seul grand exécutable.
Tout comme MainMa l'a mentionné, certaines bibliothèques sont intégrées dans des fichiers séparés, qui seront liés dynamiquement au moment de l'exécution avec l'exécutable. Ces bibliothèques sont appelées objets partagés (* .so) dans Unix et bibliothèques liées dynamiquement (DLL) dans Windows. Les bibliothèques dynamiques présentent de nombreux avantages, dont le fait que vous n'avez pas besoin de les compiler / lier, à moins que leur code source ne change effectivement.
Il existe des outils d'automatisation de construction qui vous aident à:
Les plus célèbres (make, ant, maven, ...) peuvent détecter automatiquement quelles parties du code ont été modifiées depuis la dernière compilation, et exactement quel objet / binaire doit être mis à jour.
Cependant, cela entraîne un coût (relativement faible) d'avoir à écrire un "script de construction". C'est un fichier contenant toutes les informations sur votre build, comme définir les cibles et leurs dépendances, définir quel compilateur vous voulez et quelles options utiliser, définir votre environnement de build, vos chemins de bibliothèque, ... Vous avez peut-être entendu parler de Makefiles (très commun dans le monde Unix), ou build.xml (très populaire dans le monde Java). Voilà ce qu'ils font.
la source
build.xml
fichierVous ne recompilez pas le projet entier à chaque fois. Par exemple, s'il s'agit d'une application C / C ++, il y a des chances qu'elle soit séparée en bibliothèques (DLL sous Windows), chaque bibliothèque étant compilée séparément.
Le projet lui-même est généralement compilé quotidiennement sur un serveur dédié: ce sont des builds nocturnes. Ce processus peut prendre beaucoup de temps, car il inclut non seulement le temps de compilation, mais aussi le temps passé à exécuter des tests unitaires, d'autres tests et d'autres processus.
la source
Je pense que toutes les réponses à ce jour ont également fait allusion, c'est que les grands projets logiciels sont presque toujours divisés en morceaux beaucoup plus petits. Chaque pièce est normalement stockée dans son propre fichier.
Ces pièces sont compilées individuellement pour créer des objets. Les objets sont ensuite liés entre eux pour former le produit final. [D'une certaine manière, c'est un peu comme construire des trucs à partir de Legos. Vous n'essayez pas de mouler la chose finale à partir d'un gros morceau de plastique, mais vous combinez un tas de petits morceaux pour le faire.]
Diviser le projet en morceaux qui sont compilés individuellement permet à certaines choses intéressantes de se produire.
Bâtiment incrémental
Tout d'abord, lorsque vous changez une pièce, vous n'avez généralement pas besoin de recompiler toutes les pièces. D'une manière générale, tant que vous ne modifiez pas la façon dont les autres pièces interagissent avec votre pièce, les autres n'ont pas besoin d'être recompilées.
Cela donne naissance à l'idée de construction incrémentale . Lorsque vous effectuez une génération incrémentielle, seules les parties affectées par la modification sont recompilées. Cela accélère considérablement le temps de développement. Certes, vous devrez peut-être encore attendre que tout soit rétabli, mais cela représente toujours une économie par rapport à la nécessité de recompiler et de tout relier à nouveau. (BTW: Certains systèmes / langages prennent en charge la liaison incrémentielle de sorte que seules les choses qui ont changé doivent être reliées. Le coût pour cela est généralement lié aux performances et à la taille du code.)
Tests unitaires
La deuxième chose que d'avoir de petits morceaux vous permet de faire est de tester individuellement les morceaux avant de les combiner. C'est ce qu'on appelle les tests unitaires . Dans les tests unitaires, chaque unité est testée individuellement avant d'être intégrée (combinée) avec le reste du système. Les tests unitaires sont normalement écrits afin de pouvoir être exécutés rapidement sans impliquer le reste du système.
Le cas limite d'application des tests est vu dans Test Driven Development (TDD). Dans ce modèle de développement, aucun code n'est écrit / modifié sauf pour corriger un test qui a échoué.
Pour le rendre plus facile
Donc, décomposer les choses semble bien, mais il semble également que beaucoup de travail soit nécessaire pour construire le projet: vous devez comprendre ce que les morceaux ont changé et ce qui dépend de ces morceaux, compiler chaque morceau, puis lier le tout ensemble.
Heureusement, les programmeurs sont paresseux *, ils inventent donc beaucoup d'outils pour faciliter leur travail. À cette fin, de nombreux outils ont été écrits pour automatiser la tâche ci-dessus. Les plus célèbres d'entre eux ont déjà été mentionnés (marque, fourmi, maven). Ces outils vous permettent de définir quelles pièces doivent être assemblées pour faire votre projet final et comment les pièces dépendent les unes des autres (c'est-à-dire si vous changez cela, cela doit être recompilé). Le résultat est que l'émission d'une seule commande détermine ce qui doit être recompilé, le compile et relie tout.
Mais cela laisse encore à comprendre comment les choses sont liées les unes aux autres. C'est beaucoup de travail et comme je l'ai déjà dit, les programmeurs sont paresseux. Ils ont donc trouvé une autre classe d'outils. Ces outils ont été écrits pour déterminer les dépendances pour vous! Souvent, les outils font partie des environnements de développement intégrés (IDE) comme Eclipse et Visual Studio, mais il existe également des outils autonomes utilisés pour les applications génériques et spécifiques (makedep, QMake pour les programmes Qt).
* En fait, les programmeurs ne sont pas vraiment paresseux, ils aiment juste passer leur temps à travailler sur des problèmes, pas à faire des tâches répétitives qui peuvent être automatisées par un programme.
la source
Voici ma liste de choses que vous pouvez essayer d'accélérer les builds C / C ++:
la source
L'exécution de quelque chose interprété est également très inefficace et lente, et (sans doute) erronée. Vous vous plaignez des exigences de temps sur le PC du développeur, mais ne pas compiler entraîne des exigences de temps sur le PC de l' utilisateur , ce qui est sans doute bien pire.
Plus important encore, les systèmes modernes peuvent effectuer des reconstructions incrémentielles assez avancées et il n'est pas courant de recompiler le tout pour des modifications mineures - les systèmes compilés peuvent inclure des composants de script, particulièrement communs pour des choses comme l'interface utilisateur.
la source
Si le projet implémente le DAG de dépendance de compilation appropriée, vous pouvez vous en sortir en recompilant uniquement les fichiers objets affectés par votre modification.
En supposant également un DAG de dépendance de compilation approprié, vous pouvez compiler à l'aide de plusieurs processus. Un travail par cœur / unité centrale est la norme.
Vous pouvez créer plusieurs exécutables pour les tests qui ne lient que des fichiers objets particuliers.
la source
En plus de la réponse de MainMa, nous venons également de mettre à niveau les machines sur lesquelles nous travaillons. L'un des meilleurs achats que nous ayons faits était un SSD lorsque vous ne pouvez pas vous empêcher de recompiler l'intégralité du projet.
Une autre suggestion serait d'essayer un compilateur différent. À l'époque, nous passons du compilateur Java à Jikes et nous sommes maintenant passés à l'utilisation du compilateur fourni avec Eclipse (je ne sais pas s'il a un nom) qui tire mieux parti des processeurs multicœurs.
Notre projet de 37 000 fichiers a pris environ 15 minutes à compiler à partir de zéro avant d'apporter ces modifications. Après les changements, il a été réduit à 2-3 minutes.
Bien sûr, il vaut la peine de mentionner à nouveau le point de MainMa. Ne recompilez pas l'intégralité du projet chaque fois que vous souhaitez voir un changement.
la source