J'ai un gros fichier de solution c # (~ 100 projets) et j'essaie d'améliorer les temps de construction. Je pense que "Copy Local" est un gaspillage dans de nombreux cas pour nous, mais je m'interroge sur les meilleures pratiques.
Dans notre .sln, nous avons l'application A dépendant de l'assemblage B qui dépend de l'assemblage C. Dans notre cas, il y a des dizaines de "B" et une poignée de "C". Comme ils sont tous inclus dans le .sln, nous utilisons des références de projet. Tous les assemblys sont actuellement construits dans $ (SolutionDir) / Debug (ou Release).
Par défaut, Visual Studio marque ces références de projet comme «Copier local», ce qui entraîne la copie de chaque «C» dans $ (SolutionDir) / Debug une fois pour chaque «B» généré. Cela semble inutile. Que peut-il se passer si je désactive simplement "Copier local"? Que font les autres personnes disposant de grands systèmes?
SUIVRE:
De nombreuses réponses suggèrent de diviser la construction en fichiers .sln plus petits ... Dans l'exemple ci-dessus, je construirais d'abord les classes de base "C", suivies de la plupart des modules "B", puis de quelques applications, " UNE". Dans ce modèle, j'ai besoin d'avoir des références non-projet à C à partir de B. Le problème que je rencontre là-bas est que "Debug" ou "Release" est intégré dans le chemin d'indication et je finis par construire mes versions Release de "B" contre les versions de débogage de "C".
Pour ceux d'entre vous qui ont divisé l'accumulation en plusieurs fichiers .sln, comment gérez-vous ce problème?
la source
<Private>True</Private>
dans un csproj?.sln
en plus petits rompt le calcul d'auto-dépendance de VS de<ProjectReference/>
s. Je suis passé de plusieurs plus petits.sln
à un seul gros.sln
moi-même juste parce que VS cause moins de problèmes de cette façon… Alors, peut-être que le suivi suppose une solution pas nécessairement la meilleure à la question originale? ;-)Réponses:
Dans un projet précédent, j'ai travaillé avec une grande solution avec des références de projet et j'ai également rencontré un problème de performance. La solution était triple:
Définissez toujours la propriété Copy Local sur false et appliquez-la via une étape msbuild personnalisée
Définissez le répertoire de sortie de chaque projet sur le même répertoire (de préférence par rapport à $ (SolutionDir)
Les cibles cs par défaut livrées avec le framework calculent l'ensemble de références à copier dans le répertoire de sortie du projet en cours de construction. Comme cela nécessite de calculer une fermeture transitive sous la relation «Références», cela peut devenir TRÈS coûteux. Ma solution de contournement pour cela était de redéfinir la
GetCopyToOutputDirectoryItems
cible dans un fichier de cibles commun (par exempleCommon.targets
) importé dans chaque projet après l'importation du fichierMicrosoft.CSharp.targets
. Résultat: chaque fichier de projet ressemble à ce qui suit:Cela a réduit notre temps de construction à un moment donné de quelques heures (principalement en raison de contraintes de mémoire) à quelques minutes.
Le redéfini
GetCopyToOutputDirectoryItems
peut être créé en copiant les lignes 2,438–2,450 et 2,474–2,524 deC:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets
dansCommon.targets
.Par souci d'exhaustivité, la définition cible résultante devient alors:
Avec cette solution de contournement en place, j'ai trouvé qu'il était possible d'avoir jusqu'à> 120 projets dans une seule solution, cela présente le principal avantage que l'ordre de construction des projets peut toujours être déterminé par VS au lieu de le faire à la main en fractionnant votre solution .
la source
Je vous suggère de lire les articles de Patric Smacchia sur ce sujet:
Vous pouvez également lire cet article pour vous aider à réduire le nombre de vos projets et à améliorer votre temps de compilation.
la source
Je suggère d'avoir une copie locale = false pour presque tous les projets sauf celui qui se trouve en haut de l'arborescence des dépendances. Et pour toutes les références de celle du haut, copiez local = true. Je vois de nombreuses personnes suggérant de partager un répertoire de sortie; Je pense que c'est une idée horrible basée sur l'expérience. Si votre projet de démarrage contient des références à une dll que tout autre projet contient une référence à vous, vous rencontrerez à un moment donné une violation d'accès \ partage même si copier local = false sur tout et votre build échouera. Ce problème est très ennuyeux et difficile à retracer. Je suggère complètement de rester à l'écart d'un répertoire de sortie de partition et au lieu d'avoir le projet en haut de la chaîne de dépendances, écrivez les assemblys nécessaires dans le dossier correspondant. Si vous n'avez pas de projet en haut, alors je suggérerais une copie post-build pour que tout soit au bon endroit. Aussi, j'essaierais de garder à l'esprit la facilité de débogage. Tous les projets exe que je laisse toujours copier local = true pour que l'expérience de débogage F5 fonctionne.
la source
Vous avez raison. CopyLocal tuera absolument vos temps de construction. Si vous avez une grande arborescence source, vous devez désactiver CopyLocal. Malheureusement, il n'est pas aussi facile qu'il devrait l'être de le désactiver proprement. J'ai répondu à cette question exacte sur la désactivation de CopyLocal à Comment remplacer le paramètre CopyLocal (Private) pour les références dans .NET de MSBUILD . Vérifiez-le. Ainsi que les meilleures pratiques pour les grandes solutions dans Visual Studio (2008).
Voici quelques informations supplémentaires sur CopyLocal tel que je le vois.
CopyLocal a été implémenté vraiment pour prendre en charge le débogage local. Lorsque vous préparez votre application pour l'empaquetage et le déploiement, vous devez créer vos projets dans le même dossier de sortie et vous assurer que vous disposez de toutes les références dont vous avez besoin.
J'ai écrit sur la façon de gérer la création de grandes arborescences sources dans l'article MSBuild: Meilleures pratiques pour la création de builds fiables, partie 2 .
la source
À mon avis, avoir une solution avec 100 projets est une GROSSE erreur. Vous pourriez probablement diviser votre solution en petites unités logiques valides, simplifiant ainsi la maintenance et les builds.
la source
Je suis surpris que personne n'ait mentionné l'utilisation de liens physiques. Au lieu de copier les fichiers, il crée un lien direct vers le fichier d'origine. Cela économise de l'espace disque et accélère considérablement la construction. Cela peut être activé sur la ligne de commande avec les propriétés suivantes:
/ p: CreateHardLinksForAdditionalFilesIfPossible = true; CreateHardLinksForCopyAdditionalFilesIfPossible = true; CreateHardLinksForCopyFilesToOutputDirectoryIfPossible = true; CreateHardLinksForCopyLocalIfPossible = true; CreateHardLinksForPossibleIfPossible = true; CreateHardLinksFor
Vous pouvez également l'ajouter à un fichier d'importation central afin que tous vos projets puissent également bénéficier de cet avantage.
la source
Si vous avez défini la structure de dépendance via des références de projet ou via des dépendances au niveau de la solution, il est prudent d'activer "Copier local", je dirais même que c'est une bonne pratique de le faire, car cela vous permettra d'utiliser MSBuild 3.5 pour exécuter votre build en parallèle ( via / maxcpucount) sans que différents processus ne se déclenchent l'un sur l'autre lors de la tentative de copie d'assemblys référencés.
la source
notre «meilleure pratique» est d'éviter les solutions avec de nombreux projets. Nous avons un répertoire nommé "matrix" avec les versions actuelles des assemblys, et toutes les références proviennent de ce répertoire. Si vous modifiez un projet et que vous pouvez dire "maintenant le changement est terminé", vous pouvez copier l'assemblage dans le répertoire "matrice". Ainsi, tous les projets qui dépendent de cet assemblage auront la version actuelle (= la plus récente).
Si vous avez peu de projets en solution, le processus de construction est beaucoup plus rapide.
Vous pouvez automatiser l'étape "Copier l'assemblage dans le répertoire de la matrice" en utilisant les macros de Visual Studio ou avec "menu -> outils -> outils externes ...".
la source
Vous n'avez pas besoin de modifier les valeurs CopyLocal. Tout ce que vous avez à faire est de prédéfinir un $ (OutputPath) commun pour tous les projets de la solution et de prédéfinir $ (UseCommonOutputDirectory) sur true. Voir ceci: http://blogs.msdn.com/b/kirillosenkov/archive/2015/04/04/using-a-common-intermediate-and-output-directory-for-your-solution.aspx
la source
Définir CopyLocal = false réduira le temps de génération, mais peut entraîner différents problèmes lors du déploiement.
Il existe de nombreux scénarios, lorsque vous devez laisser Copy Local 'à True, par exemple
Les problèmes possibles décrits dans les questions du SO
" Quand doit-il être défini sur true et quand ne devrait-il pas être défini? ",
" Message d'erreur" Impossible de charger un ou plusieurs des types demandés. Récupérez la propriété LoaderExceptions pour plus d'informations. " »
et la réponse d ' aaron-stainback à cette question.
Mon expérience avec la définition de CopyLocal = false n'a PAS réussi. Voir mon article de blog "Ne pas modifier les références de projet" Copier local "à false, sauf si vous comprenez les sous-séquences."
Le temps de résoudre les problèmes surpondère les avantages de la définition de copyLocal = false.
la source
CopyLocal=False
causera certainement des problèmes, mais il existe des solutions à ceux-ci. Aussi, vous devriez corriger le formatage de votre blog, il est à peine lisible, et dire là que "j'ai été averti par <random consultant> de <random company> des erreurs possibles lors des déploiements" n'est pas un argument. Vous devez vous développer.J'ai tendance à construire dans un répertoire commun (par exemple .. \ bin), donc je peux créer de petites solutions de test.
la source
Vous pouvez essayer d'utiliser un dossier dans lequel tous les assemblys partagés entre les projets seront copiés, puis créer une variable d'environnement DEVPATH et la définir
<developmentMode developerInstallation="true" />
dans le fichier machine.config sur le poste de travail de chaque développeur. La seule chose que vous devez faire est de copier toute nouvelle version dans votre dossier où pointe la variable DEVPATH.
Divisez également votre solution en quelques solutions plus petites si possible.
la source
Ce n'est peut-être pas la meilleure pratique, mais c'est ainsi que je travaille.
J'ai remarqué que Managed C ++ vidait tous ses binaires dans $ (SolutionDir) / 'DebugOrRelease'. J'ai donc vidé tous mes projets C # là aussi. J'ai également désactivé la "Copie locale" de toutes les références aux projets dans la solution. J'ai eu une amélioration notable du temps de construction dans ma petite solution de 10 projets. Cette solution est un mélange de projets C #, C ++ géré, C ++ natif, C # webservice et d'installation.
Peut-être que quelque chose est cassé, mais comme c'est la seule façon de travailler, je ne le remarque pas.
Il serait intéressant de savoir ce que je brise.
la source
Habituellement, vous n'avez besoin de Copier Local que si vous voulez que votre projet utilise la DLL qui se trouve dans votre Bin par rapport à ce qui se trouve ailleurs (le GAC, d'autres projets, etc.)
J'aurais tendance à être d'accord avec les autres pour dire que vous devriez également essayer, si possible, de briser cette solution.
Vous pouvez également utiliser Configuration Manager pour créer vous-même différentes configurations de construction au sein de cette solution qui ne construira que des ensembles de projets donnés.
Il semblerait étrange que les 100 projets reposent les uns sur les autres, vous devriez donc pouvoir soit le diviser, soit utiliser Configuration Manager pour vous aider.
la source
Vous pouvez avoir vos références de projets pointant vers les versions de débogage des dll. Que sur votre script msbuild, vous pouvez définir le
/p:Configuration=Release
, ainsi vous aurez une version finale de votre application et de tous les assemblys satellites.la source
Si vous souhaitez disposer d'un emplacement central pour référencer une DLL en utilisant la copie locale, false échouera sans le GAC, sauf si vous le faites.
http://nbaked.wordpress.com/2010/03/28/gac-alternative/
la source
Si la référence n'est pas contenue dans le GAC, nous devons définir Copy Local sur true pour que l'application fonctionne, si nous sommes sûrs que la référence sera préinstallée dans le GAC, elle peut être définie sur false.
la source
Eh bien, je ne sais certainement pas comment les problèmes fonctionnent, mais j'ai été en contact avec une solution de construction qui s'est aidée de telle sorte que tous les fichiers créés ont été placés sur un disque virtuel à l'aide de liens symboliques .
c: \ dossier solution \ obj -> ramdisk r: \ dossier solution \ obj \
Vous pouvez également indiquer au studio visuel quel répertoire temporaire il peut utiliser pour la construction.
En fait, ce n'était pas tout ce qu'il faisait. Mais cela a vraiment touché ma compréhension de la performance.
Utilisation à 100% du processeur et un énorme projet en moins de 3 minutes avec toutes les dépendances.
la source