2011-05-23 3 views
7

Estoy tratando de acelerar nuestra compilación (csharp, msbuild, .net 3.5). Reemplazar copia con fsutil hardlink create.Acelere msbuild con fsutil hardlink create en lugar de tareas de copia lenta

Anteriormente, casi lo tengo con ejecutar un script sobre archivos sln y hacer que las referencias dll sean privadas = falsas, y luego tener un evento de creación posterior crea los enlaces duros. El problema es que las dependencias transitivas no están incluidas. Por lo tanto, creo que necesito hacer referencia a la tarea ResolveAssemblyReference en msbuild para obtener las dependencias transitivas que necesito enlazar.

¿Alguna idea?

This persona intentó lo mismo, pero no publicó una solución final.

Para ser claro: lo que quiero es mantener directorios bin separados, pero en lugar de copiar archivos de uno a otro para crear un enlace duro de una fuente (de una referencia o una dependencia) al destino (el proyecto actual compartimiento). Que es mucho más rápido y da aproximadamente el mismo efecto que copiar.

+1

Por qué no estableció un DEVPATH a toda la papelera de carpetas en su lugar. Entonces no necesita hacer nada, excepto apagar copylocal. http://blogs.msdn.com/b/junfeng/archive/2005/12/13/503059.aspx – adrianm

Respuesta

6

Esto es compatible con VS 2010. Pero no 2008. Consulte la opción UseHardLinksIfPossible para Copiar en _CopyFilesMarkedCopyLocal.

Véase también http://social.msdn.microsoft.com/Forums/en/tfsbuild/thread/9382a3d8-4632-4826-ad15-d5e845080981, http://msdn.microsoft.com/en-us/library/ms171466(v=VS.90).aspx para contexto.

Reemplazar el objetivo _CopyFilesMarkedCopyLocal. Agregamos algo como esto a los archivos csproj en la parte inferior: <Import Project="..\..\..\..\..\\CommonBuild\TW.Override.Microsoft.Common.targets" /> (Esto se agrega automáticamente al archivo con una tarea nant en cada compilación nant completa, por lo que cada proyecto se beneficia).

Nuestro archivo de nuevos objetivos es:

 
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <UsingTask TaskName="CopyWithHardlinkOption" AssemblyFile="..\lib\TWBuildOptimization\TW.Hardlinker.dll" /> 
    <!-- 
    ============================================================ 
             _CopyFilesMarkedCopyLocal 
    Overridden in order to allow hardlinking with our custom Copy Task.           

    Hardlinking is a major performance improvement. Sometimes 50% of the time compared to copying. 

    Copy references that are marked as "CopyLocal" and their dependencies, including .pdbs, .xmls and satellites. 
    ============================================================ 
    --> 
    <Target 
     Name="_CopyFilesMarkedCopyLocal"> 
     <CopyWithHardlinkOption 
      SourceFiles="@(ReferenceCopyLocalPaths)" 
      DestinationFiles="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" 
      SkipUnchangedFiles="true" 
       UseHardlinksIfPossible="true" 
      OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"> 
      <Output TaskParameter="DestinationFiles" ItemName="FileWritesShareable"/> 
     </CopyWithHardlinkOption> 
    </Target> 
</Project> 

ver la opción de msbuild 4 Copia UseHardlinksIfPossible. Transporté eso a 3.5 mediante la descompilación y la reimplementación. La lógica relevante en CopyFileWithLogging fue:

 // The port from 4.0's task that allows hardlinking 
     bool hardlinkSucceeded = false; 
     if (UseHardlinksIfPossible) 
     { 
      if (File.Exists(destinationFile)) 
      { 
       FileUtilities.DeleteNoThrow(destinationFile); 
      } 
      if (!TwNativeMethods.CreateHardLink(destinationFile, sourceFile, IntPtr.Zero)) 
      { 
       var win32Exception = new Win32Exception(Marshal.GetLastWin32Error()); 
       Log.LogMessage(MessageImportance.High, "Hardlinking had a problem {0}, will retry copying. {1}", new object[] {win32Exception.Message, win32Exception}); 
      } 
      hardlinkSucceeded = true; 
     } 
     if (!hardlinkSucceeded) 
     { 
      Log.LogMessageFromResources(MessageImportance.Normal, "Copy.FileComment", new object[] { sourceFile, destinationFile }); 
      Log.LogMessageFromResources(MessageImportance.Low, "Shared.ExecCommand", new object[0]); 
      Log.LogCommandLine(MessageImportance.Low, "copy /y \"" + sourceFile + "\" \"" + destinationFile + "\""); 
      File.Copy(sourceFile, destinationFile, true); 
     } 
     // end port 

también tuvo que añadir los siguientes:

// decompiled from 4.0 
internal static class TwNativeMethods 
{ 
    [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] 
    internal static extern bool CreateHardLink(string newFileName, string exitingFileName, IntPtr securityAttributes); 
} 

// decompiled from 4.0 
internal static class FileUtilities 
{ 
    internal static void DeleteNoThrow(string path) 
    { 
     try 
     { 
      File.Delete(path); 
     } 
     catch (Exception exception) 
     { 
      if (ExceptionHandling.NotExpectedException(exception)) 
      { 
       throw; 
      } 
     } 
    } 
} 

// decompiled from 4.0 
internal static class ExceptionHandling 
{ 
    // Methods 
    internal static bool IsCriticalException(Exception e) 
    { 
     return (((e is StackOverflowException) || (e is OutOfMemoryException)) || ((e is ExecutionEngineException) || (e is AccessViolationException))); 
    } 

    internal static bool NotExpectedException(Exception e) 
    { 
     return (((!(e is UnauthorizedAccessException) && !(e is ArgumentNullException)) && (!(e is PathTooLongException) && !(e is DirectoryNotFoundException))) && ((!(e is NotSupportedException) && !(e is ArgumentException)) && (!(e is SecurityException) && !(e is IOException)))); 
    } 

    internal static bool NotExpectedReflectionException(Exception e) 
    { 
     return ((((!(e is TypeLoadException) && !(e is MethodAccessException)) && (!(e is MissingMethodException) && !(e is MemberAccessException))) && ((!(e is BadImageFormatException) && !(e is ReflectionTypeLoadException)) && (!(e is CustomAttributeFormatException) && !(e is TargetParameterCountException)))) && (((!(e is InvalidCastException) && !(e is AmbiguousMatchException)) && (!(e is InvalidFilterCriteriaException) && !(e is TargetException))) && (!(e is MissingFieldException) && NotExpectedException(e)))); 
    } 
} 
+0

¿Hay alguna manera de forzar a msbuild a mover archivos (o crear enlaces duros para ese asunto) de \ obj \ debug a \ bin \ debug en lugar de copiar? – ya23

+0

@ ya23 Creo que dll/exe presente en \ obj no son los mismos que en \ bin. – Ankush

0

¿Ha intentado definir su propio objetivo que se ejecuta después del objetivo ResolveAssemblyReferences? Después de que se haya ejecutado ResolveAssemblyReferences, debería poder utilizar el elemento @ (ReferencePath) para dirigir la creación de su enlace. Considere la implementación de AfterResolveReferences, que en Microsoft.Common.targets es solo un marcador de posición vacío que puede anular.

+0

Gracias, al final sobrepaso la tarea local de copia de MsBuild para crear enlaces duros en lugar de copiar el cierre transitivo de referencias. Espero abrir la fuente si ayuda a otras personas. Y planee publicar una respuesta más detallada y marque la pregunta respondida. – JAWspeak

Cuestiones relacionadas