c# - 使用 fsutil hardlink create 而不是缓慢的复制任务来加速 msbuild

标签 c# .net msbuild

我正在努力加快构建速度(csharp、msbuild、.net 3.5)。将副本替换为 fsutil hardlink create。

以前,我几乎通过在 sln 文件上运行脚本并使 dll 引用私有(private) = false,然后让构建后事件创建硬链接(hard link)来实现它。问题是不包括传递依赖项。所以,我想我需要引用 ResolveAssemblyReference msbuild 中的任务以获取我需要硬链接(hard link)的传递依赖项。

有什么想法吗?

This有人尝试过同样的事情,但没有发布最终解决方案。

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

最佳答案

这在 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 任务,因此每个项目都会受益)。

我们的新目标文件是:

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

See the msbuild 4 Copy UseHardlinksIfPossible option. I backported that to 3.5 through decompiling and reimplementing. The relevant logic in CopyFileWithLogging was:

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

关于c# - 使用 fsutil hardlink create 而不是缓慢的复制任务来加速 msbuild,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6096290/

相关文章:

.net - Umbraco 与 DotNetNuke : can't decide which one is more suitable

visual-studio - 仅在需要时和/或部分运行npm install

msbuild - 如何将 NuGet contentFiles 提取到特定目录?

c# - 如何处理 Automapper 异常(try/catch)

c# - 暂停发布到完整的 BufferAction

c# - 使用 Linq 从数组构建字典

c# - 在 Travis CI 上使用 Mono 5.14.0.177、msbuild 15.0、nuget 4.7.1 构建失败,但在 VirtualBox 中无法重现

c# - `InstallPixels()` 和 `SetPixels()` 中的 `SkiaSharp.SKBitmap` 有什么区别?

c# - EF Core 3.1 更新实体

c# - 需要什么来证明本契约(Contract)的要求?