visual tutorial studio proyecto para outpath genera descargar configurar code assemblyname c# .net visual-studio msbuild

c# - tutorial - ¿Cuál es la mejor práctica para "Copiar local" y con las referencias del proyecto?



visual studio code c# (18)

Bueno, ciertamente no sé cómo funcionan los problemas, pero tuve contacto con una solución de compilación que se ayudó a sí misma de tal manera que todos los archivos creados se pusieron en un ramdisk con la ayuda de enlaces simbólicos .

  • c: / carpeta de la solución / bin -> ramdisk r: / carpeta de la solución / bin /
  • c: / carpeta de la solución / obj -> ramdisk r: / carpeta de la solución / obj /

  • También puede indicarle al estudio visual qué directorio temporal puede usar para la compilación.

En realidad, eso no fue todo lo que hizo. Pero realmente me impactó mi comprensión del rendimiento.
Uso del procesador al 100% y un gran proyecto en menos de 3 minutos con todas las dependencias.

Tengo un gran archivo de solución c # (~ 100 proyectos) y estoy tratando de mejorar los tiempos de compilación. Creo que "Copiar local" es un desperdicio en muchos casos para nosotros, pero me pregunto acerca de las mejores prácticas.

En nuestro .sln, tenemos la aplicación A dependiendo del ensamblaje B, que depende del ensamblaje C. En nuestro caso, hay docenas de "B" y un puñado de "C". Dado que todos están incluidos en .sln, estamos usando referencias de proyectos. Todos los ensamblados actualmente incorporan $ (SolutionDir) / Debug (o Release).

De forma predeterminada, Visual Studio marca estas referencias de proyecto como "Copiar local", lo que da como resultado que cada "C" se copie en $ (SolutionDir) / Debug una vez por cada "B" que se genera. Esto parece un desperdicio ¿Qué puede salir mal si solo desactivo "Copiar local"? ¿Qué hacen otras personas con sistemas grandes?

SEGUIR:

Muchas respuestas sugieren dividir la compilación en archivos .sln más pequeños ... En el ejemplo anterior, primero crearía las clases de cimentación "C", seguidas por la mayoría de los módulos "B" y luego algunas aplicaciones ". UN". En este modelo, necesito tener referencias de C de B que no sean de proyecto. El problema que encuentro allí es que "Debug" o "Release" se cuelan en la ruta de sugerencias y termino construyendo mis compilaciones de Release de "B" contra versiones de depuración de "C".

Para aquellos de ustedes que dividen la compilación en múltiples archivos .sln, ¿cómo manejan este problema?


En mi opinión, tener una solución con 100 proyectos es un GRAN error. Probablemente pueda dividir su solución en unidades lógicas pequeñas y válidas, simplificando tanto el mantenimiento como las construcciones.


En un proyecto anterior, trabajé con una gran solución con referencias de proyectos y también tropecé con un problema de rendimiento. La solución fue triple:

  1. Establezca siempre la propiedad Copiar local en falso y aplique esto a través de un paso personalizado de msbuild

  2. Establezca el directorio de salida para cada proyecto en el mismo directorio (preferiblemente relativo a $ (SolutionDir)

  3. Los destinos predeterminados de cs que se envían con el marco calculan el conjunto de referencias que se copiarán en el directorio de salida del proyecto que se está construyendo actualmente. Como esto requiere calcular un cierre transitivo bajo la relación ''Referencias'', esto puede volverse MUY costoso. Mi solución para esto fue redefinir el objetivo GetCopyToOutputDirectoryItems en un archivo de objetivos comunes (por ejemplo, Common.targets ) que se importa en cada proyecto después de la importación de Microsoft.CSharp.targets . Resultando en que cada archivo de proyecto se vea como el siguiente:

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> ... snip ... </ItemGroup> <Import Project="$(MSBuildBinPath)/Microsoft.CSharp.targets" /> <Import Project="[relative path to Common.targets]" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> </Target> <Target Name="AfterBuild"> </Target> --> </Project>

Esto redujo nuestro tiempo de construcción en un tiempo dado de un par de horas (principalmente debido a restricciones de memoria), a un par de minutos.

Los GetCopyToOutputDirectoryItems redefinidos se pueden crear copiando las líneas 2,438-2,450 y 2,474-2,524 de C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Microsoft.Common.targets en Common.targets .

Para completar, la definición del objetivo resultante se convierte en:

<!-- This is a modified version of the Microsoft.Common.targets version of this target it does not include transitively referenced projects. Since this leads to enormous memory consumption and is not needed since we use the single output directory strategy. ============================================================ GetCopyToOutputDirectoryItems Get all project items that may need to be transferred to the output directory. ============================================================ --> <Target Name="GetCopyToOutputDirectoryItems" Outputs="@(AllItemsFullPathWithTargetPath)" DependsOnTargets="AssignTargetPaths;_SplitProjectReferencesByFileExistence"> <!-- Get items from this project last so that they will be copied last. --> <CreateItem Include="@(ContentWithTargetPath->''%(FullPath)'')" Condition="''%(ContentWithTargetPath.CopyToOutputDirectory)''==''Always'' or ''%(ContentWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''" > <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways" Condition="''%(ContentWithTargetPath.CopyToOutputDirectory)''==''Always''"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory" Condition="''%(ContentWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''"/> </CreateItem> <CreateItem Include="@(_EmbeddedResourceWithTargetPath->''%(FullPath)'')" Condition="''%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)''==''Always'' or ''%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''" > <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways" Condition="''%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)''==''Always''"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory" Condition="''%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''"/> </CreateItem> <CreateItem Include="@(Compile->''%(FullPath)'')" Condition="''%(Compile.CopyToOutputDirectory)''==''Always'' or ''%(Compile.CopyToOutputDirectory)''==''PreserveNewest''"> <Output TaskParameter="Include" ItemName="_CompileItemsToCopy"/> </CreateItem> <AssignTargetPath Files="@(_CompileItemsToCopy)" RootFolder="$(MSBuildProjectDirectory)"> <Output TaskParameter="AssignedFiles" ItemName="_CompileItemsToCopyWithTargetPath" /> </AssignTargetPath> <CreateItem Include="@(_CompileItemsToCopyWithTargetPath)"> <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways" Condition="''%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)''==''Always''"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory" Condition="''%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''"/> </CreateItem> <CreateItem Include="@(_NoneWithTargetPath->''%(FullPath)'')" Condition="''%(_NoneWithTargetPath.CopyToOutputDirectory)''==''Always'' or ''%(_NoneWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''" > <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways" Condition="''%(_NoneWithTargetPath.CopyToOutputDirectory)''==''Always''"/> <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory" Condition="''%(_NoneWithTargetPath.CopyToOutputDirectory)''==''PreserveNewest''"/> </CreateItem> </Target>

Con esta solución en funcionamiento, encontré factible tener tanto como> 120 proyectos en una solución, esto tiene el beneficio principal de que el orden de construcción de los proyectos aún puede ser determinado por VS en lugar de hacerlo a mano al dividir su solución .


Estás en lo correcto. CopyLocal absolutamente matará sus tiempos de construcción. Si tiene un árbol fuente grande, entonces debe deshabilitar CopyLocal. Desafortunadamente no es tan fácil como debería ser desactivarlo limpiamente. He respondido esta pregunta exacta sobre la inhabilitación de CopyLocal en Cómo anulo la configuración CopyLocal (privada) para las referencias en .NET de MSBUILD . Echale un vistazo. Además de las mejores prácticas para soluciones grandes en Visual Studio (2008).

Aquí hay más información sobre CopyLocal como lo veo.

CopyLocal se implementó realmente para admitir la depuración local. Cuando prepare la aplicación para el empaquetado y la implementación, debe construir sus proyectos en la misma carpeta de salida y asegurarse de tener todas las referencias que necesita allí.

He escrito sobre cómo tratar con la construcción de grandes fuentes de árboles en el artículo MSBuild: Mejores prácticas para crear construcciones confiables, Parte 2 .


Esta puede no ser la mejor práctica, pero así es como trabajo.

Me di cuenta de que Managed C ++ volca todos sus binarios en $ (SolutionDir) / ''DebugOrRelease''. Así que dejé todos mis proyectos de C # allí también. También apagué el "Copiar local" de todas las referencias a proyectos en la solución. Tuve una notable mejora en el tiempo de construcción en mi pequeña solución de 10 proyectos. Esta solución es una mezcla de C #, C ++ administrado, C ++ nativo, C # webservice y proyectos de instalador.

Tal vez algo está roto, pero como esta es la única forma en que trabajo, no me doy cuenta.

Sería interesante descubrir lo que estoy rompiendo.


Establecer CopyLocal = false reducirá el tiempo de compilación, pero puede causar diferentes problemas durante la implementación.

Hay muchos escenarios, cuando necesita tener Copy Local ''left to True, por ejemplo

  • Proyectos de alto nivel,
  • Dependencias de segundo nivel,
  • DLL llamado por reflexión

Los posibles problemas descritos en las preguntas de SO
"¿ Cuándo se debe establecer copy-local en verdadero y cuándo no? ",
" Mensaje de error" No se pueden cargar uno o más de los tipos solicitados. Recupere la propiedad LoaderExceptions para obtener más información. "
y la answer para esta pregunta.

Mi experiencia con la configuración de CopyLocal = false NO fue exitosa. Ver la entrada de mi blog "NO cambiar" Copiar local "proyecto referencias a falso, a menos que entienda subsequences".

El tiempo para resolver los problemas tiene sobrepeso los beneficios de configurar copyLocal = false.


Le sugiero que lea los artículos de Patric Smacchia sobre ese tema:

Los proyectos CC.Net VS se basan en la opción de ensamblaje de referencia local de copia establecida en verdadero. [...] Esto no solo aumenta significativamente el tiempo de compilación (x3 en el caso de NUnit), sino que también arruina su entorno de trabajo. Por último, pero no menos importante, al hacerlo, se presenta el riesgo de problemas potenciales de las versiones. Por cierto, NDepend emitirá una advertencia si encuentra 2 conjuntos en 2 directorios diferentes con el mismo nombre, pero no el mismo contenido o versión.

Lo correcto es definir 2 directorios $ RootDir $ / bin / Debug y $ RootDir $ / bin / Release, y configurar sus proyectos de VisualStudio para que emitan ensamblados en estos directorios. Todas las referencias de proyectos deben hacer referencia a los ensamblados en el directorio Debug.

También puede leer este artículo para ayudarlo a reducir el número de sus proyectos y mejorar su tiempo de compilación.


Me sorprende que nadie haya mencionado el uso de enlaces duros. En lugar de copiar los archivos, crea un enlace fijo al archivo original. Esto ahorra espacio en disco y acelera la construcción. Esto puede habilitarse en la línea de comando con las siguientes propiedades:

/ p: CreateHardLinksForAdditionalFilesIfPossible = true; CreateHardLinksForCopyAdditionalFilesIfPossible = true; CreateHardLinksForCopyFilesToOutputDirectoryIfPossible = true; CreateHardLinksForCopyLocalIfPossible = true; CreateHardLinksForPublishFilesIfPossible = true

También puede agregar esto a un archivo central de importación para que todos sus proyectos también puedan obtener este beneficio.



Por lo general, solo necesita copiar Local si desea que su proyecto use la DLL que está en su Contenedor frente a lo que está en otro lugar (el GAC, otros proyectos, etc.)

Tiendo a estar de acuerdo con las otras personas en que también debes intentar, si es posible, romper esa solución.

También puede usar Configuration Manager para crear diferentes configuraciones de compilación dentro de esa única solución que solo generará determinados conjuntos de proyectos.

Parecería extraño si los 100 proyectos dependieran el uno del otro, por lo que debería poder dividirlo o usar Configuration Manager para ayudarse a sí mismo.


Puede hacer que las referencias de sus proyectos apunten a las versiones de depuración de los dlls. Que en su secuencia de comandos msbuild, puede configurar /p:Configuration=Release , por lo tanto, tendrá una versión de lanzamiento de su aplicación y todos los conjuntos de satélites.


Puede intentar utilizar una carpeta donde se copiarán todos los ensamblados que se comparten entre proyectos, luego crear una variable de entorno DEVPATH y establecer

<developmentMode developerInstallation="true" />

en el archivo machine.config en la estación de trabajo de cada desarrollador. Lo único que debe hacer es copiar cualquier versión nueva en su carpeta donde señale la variable DEVPATH.

También divida su solución en algunas soluciones más pequeñas si es posible.



Si la referencia no está contenida en el GAC, debemos configurar Copy Local en verdadero para que la aplicación funcione; si estamos seguros de que la referencia estará preinstalada en el GAC, se puede establecer en falso.


Si tienes definida la estructura de dependencia a través de referencias de proyecto oa través de dependencias de nivel de solución, es seguro activar "Copiar local", incluso diría que es una práctica recomendada, ya que eso te permitirá usar MSBuild 3.5 para ejecutar tu compilación en paralelo ( via / maxcpucount) sin procesos diferentes tropezando entre sí al intentar copiar ensambles referenciados.


Sugiero que copie local = false para casi todos los proyectos, excepto el que se encuentra en la parte superior del árbol de dependencias. Y para todas las referencias en el conjunto superior, copie local = true. Veo a mucha gente sugiriendo compartir un directorio de salida; Creo que esta es una idea horrible basada en la experiencia. Si su proyecto de inicio contiene referencias a un archivo DLL que cualquier otro proyecto contiene una referencia, en algún momento experimentará una infracción de acceso / uso compartido incluso si copia local = falso en todo y su compilación fallará. Este problema es muy molesto y difícil de rastrear. Sugiero por completo que se mantenga alejado de un directorio de salida de fragmentos y en lugar de tener el proyecto en la parte superior de la cadena de dependencias, escriba los ensamblajes necesarios en la carpeta correspondiente. Si no tiene un proyecto en la "parte superior", sugeriría una copia posterior a la construcción para que todo esté en el lugar correcto. Además, trataría de recordar la facilidad de la depuración. Todos los proyectos exe que todavía deje copian local = true para que la experiencia de depuración F5 funcione.


Tiendo a construir en un directorio común (por ejemplo, / bin), así puedo crear pequeñas soluciones de prueba.


nuestra "mejor práctica" es evitar soluciones con muchos proyectos. Tenemos un directorio llamado "matriz" con versiones actuales de ensamblajes, y todas las referencias son de este directorio. Si cambia algún proyecto y puede decir "ahora el cambio está completo", puede copiar el ensamblaje en el directorio "matriz". Entonces, todos los proyectos que dependen de este ensamblado tendrán la versión actual (= última).

Si tiene pocos proyectos en solución, el proceso de compilación es mucho más rápido.

Puede automatizar el paso "copiar el ensamblaje al directorio de la matriz" utilizando las macros de Visual Studio o con "menú -> herramientas -> herramientas externas ...".