什么是&QUOT的最佳做法;复制本地"并与项目引用? [英] What is the best practice for "Copy Local" and with project references?

查看:285
本文介绍了什么是&QUOT的最佳做法;复制本地"并与项目引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个大型的C#解决方案文件(〜100项目),我试图以提高生成时间。我认为复制本地是一种浪费在许多情况下我们,但我想知道的最佳做法。

I have a large c# solution file (~100 projects), and I am trying to improve build times. I think that "Copy Local" is wasteful in many cases for us, but I am wondering about best practices.

在我们的.sln我们有应用程序A取决于程序集B依赖于组装C.在我们的案例上,有几十个B和一些C的。由于这些都包括在的.sln,我们使用项目引用。所有组件目前建设成$(SolutionDir)/调试(或释放)。

In our .sln, we have application A depending on assembly B which depends on assembly C. In our case, there are dozens of "B" and a handful of "C". Since these are all included in the .sln, we're using project references. All assemblies currently build into $(SolutionDir)/Debug (or Release).

在默认情况下,Visual Studio将标志着这些项目引用的复制本地,从而导致每个C被复制到$(SolutionDir)/调试一次,每一个B的构建。这似乎是一种浪费。有什么可以去错了,如果我只是把复制本地了吗?什么是其他人的大系统呢?

By default, Visual Studio marks these project references as "Copy Local", which results in every "C" being copied into $(SolutionDir)/Debug once for every "B" that builds. This seems wasteful. What can go wrong if I just turn "Copy Local" off? What do other people with large systems do?

后续:

很多的响应建议打破了构建成更小的.sln文件...在上面的例子中,我将建立之后大头B的模块的基础类C第一,然后几个应用程序,A。在这个模型中,我需要有非项目引用到C来自B.我碰到有问题的是,调试或释放被烤成提示路径和我风建设我发布版本B的针对调试版本的C。

Lots of responses suggest breaking up the build into smaller .sln files... In the example above, I would build the foundation classes "C" first, followed by the bulk of the modules "B", and then a few applications, "A". In this model, I need to have non-project references to C from B. The problem I run into there is that "Debug" or "Release" gets baked into the hint path and I wind up building my Release builds of "B" against debug builds of "C".

对于那些你了拆分构建成多的.sln文件,您如何管理这个问题?

For those of you that split the build up into multiple .sln files, how do you manage this problem?

推荐答案

在一个previous项目中,我曾与一个大的解决方案,项目引用,并撞到了性能问题,以及。该解决方案是三方面:

In a previous project I worked with one big solution with project references and bumped into a performance problem as well. The solution was three fold:

  1. 始终将复制本地属性设置为false,并通过自定义的MSBuild步执行本

  1. Always set the Copy Local property to false and enforce this via a custom msbuild step

设置每个项目相同的目录pferably相对于$输出目录($ P $(SolutionDir)

Set the output directory for each project to the same directory (preferably relative to $(SolutionDir)

这得到附带框架的默认CS指标计算引用的集合被复制到目前在建项目的输出目录。因为这需要计算引用的关系下一个传递闭包这会成为非常昂贵。我的解决方法,这是重新定义 GetCop​​yToOutputDirectoryItems 目标在一个共同的目标文件(例如, Common.targets )这是进口在 Microsoft.CSharp.targets在导入后的每个项目。致使每一个项目文件如下所示:

The default cs targets that get shipped with the framework calculate the set of references to be copied to the output directory of the project currently being built. Since this requires calculating a transitive closure under the 'References' relation this can become VERY costly. My workaround for this was to redefine the GetCopyToOutputDirectoryItems target in a common targets file (eg. Common.targets ) that's imported in every project after the import of the Microsoft.CSharp.targets. Resulting in every project file to look like the following:

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

这降低了我们的建造时间从几小时(主要是由于内存限制)给定的时间,在几分钟的时间。

This reduced our build time at a given time from a couple of hours (mostly due to memory constraints), to a couple of minutes.

重新定义的 GetCop​​yToOutputDirectoryItems 可以通过复制线2,438&ndash的创建; 2450 2474&ndash的; 2,524从 C:\ WINDOWS \ Microsoft.NET \框架\ V2.0.50727 \ Microsoft.Common.targets Common.targets

The redefined GetCopyToOutputDirectoryItems can be created by copying the lines 2,438–2,450 and 2,474–2,524 from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets into Common.targets.

有关完整性所产生的目标定义就变成了:

For completeness the resulting target definition then becomes:

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

使用此解决办法的地方,我发现可行有尽可能多的为> 120个项目中的一个解决方案是,这样做的主要好处,这些项目的构建顺序仍然可以通过VS,而不是这样做手工通过拆分决定你的解决方案。

With this workaround in place I found it workable to have as much as > 120 projects in one solution, this has the main benefit that the build order of the projects can still be determined by VS instead of doing that by hand by splitting up your solution.

这篇关于什么是&QUOT的最佳做法;复制本地&QUOT;并与项目引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆