使用fsutil hardlink create而不是慢速复制任务加快msbuild

本文关键字:复制 任务 msbuild hardlink fsutil create 使用 | 更新日期: 2023-09-27 17:57:29

我正在努力加快我们的构建(csharp、msbuild、.net 3.5)。用fsutil hardlink create替换copy。

以前,我几乎是通过在sln文件上运行脚本并使dll引用private=false,然后让一个构建后事件创建硬链接来实现的。问题是不包括可传递的依赖项。因此,我认为我需要在msbuild中引用ResolveAssemblyReference任务,以获得硬链接所需的可传递依赖项。

有什么想法吗?

这个人尝试了同样的方法,但没有发布最终的解决方案。

需要明确的是:我想要的是保留单独的bin目录,而不是将文件从一个复制到另一个,以创建从源(引用或依赖项)到目标(当前项目的bin)的硬链接。这要快得多,并且提供与复制大致相同的效果。

使用fsutil hardlink create而不是慢速复制任务加快msbuild

VS 2010支持此功能。但不是2008年。请参阅_CopyFilesMarkedCopyLocal中的UseHardLinksIfPossible复制选项。

另请参阅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获取上下文。

覆盖_CopyFilesMarkedCopyLocal目标。我们在底部的csproj文件中添加了这样的内容:<Import Project="..'..'..'..'..''CommonBuild'TW.Override.Microsoft.Common.targets" />(在每个完整的nant构建中,它都会自动添加到带有nant任务的文件中,因此每个项目都会受益)。

我们的新目标文件是:

<项目工具Version="3.5"DefaultTargets="Build"xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><UsingTask TaskName="CopyWithHardlinkOption"AssemblyFile="..''lib''TWBuildOptimization ''TW.Hardlinker.dll"/>&lt--============================================================_CopyFilesMarkedCopyLocal重写以便允许与我们的自定义复制任务硬链接。硬链接是一个主要的性能改进。有时50%的时间与复制相比。复制标记为"CopyLocal"的引用及其依赖项,包括.pdbs、.xml和satellite。============================================================--><目标Name="_CopyFilesMarkedCopyLocal"><使用硬链接选项复制SourceFiles="@(ReferencePyLocalPaths)"DestinationFiles="@(ReferencePyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(文件名)%(扩展名)')"SkipUnchangedFiles="true"UseHardlinksIfPossible="true"OverwriteReadOnlyFiles="$(OverwriteReadOnly Files)"><输出任务参数="DestinationFiles"项目名称="FileWritesShareable"/><使用硬链接选项复制><目标><项目>

请参阅msbuild 4 Copy UseHardlinksIfPossible选项。我通过反编译和重新实现将其移植到3.5。CopyFileWithLogging中的相关逻辑为:

      // 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

还必须添加以下内容:

// 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))));
    }
}

您是否尝试定义在ResolveAssemblyReferences目标之后运行的自己的目标?ResolveAssemblyReferences运行后,您应该能够使用@(ReferencePath)项来驱动链接创建。考虑实现AfterResolveReferences,它在Microsoft.Common.targets中只是一个供您重写的空占位符。