为什么MSBuild重建共享项目?

时间:2015-05-22 17:44:16

标签: c# visual-studio msbuild

我试图通过仅编译一次共享项目来加速一组解决方案的编译。这是对我的问题的简化描述。

我有两个解决方案 - one.sln和two.sln。它们都包含共享项目shared.csproj。我在Visual Studio中打开两个解决方案,清除它们,然后构建one.sln,然后构建two.sln。构建two.sln时,不会重新生成shared.dll,这是我期望的行为。

为了自动执行此过程,我创建了一个msbuild .proj文件(如下所示)。当我在.proj文件上调用msbuild时,会为两个解决方案重新编译shared.dll。我做错了什么?

<Project ToolsVersion="4.0" 
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         DefaultTargets="Build">
    <ItemGroup>
        <Solution Include="C:\one.sln"/>
        <Solution Include="C:\two.sln"/>
    </ItemGroup>
    <Target Name="Build">
      <MSBuild Projects="@(Solution)" Targets="Build" RunEachTargetSeparately="false" StopOnFirstFailure="true" />
    </Target>
 </Project>

3 个答案:

答案 0 :(得分:3)

IIRC,参考编译两次的原因是它在两个解决方案中都被声明为参考项目。因此,两者都将调用Build Target作为参考。这就是我理解的方式。

为参考项目创建一个项目组

  <!--Project reference-->
  <ItemGroup>
    <ProjectReference Include="refProject\refProject.csproj">
      <Targets>Build</Targets>
    </ProjectReference>
  </ItemGroup>

添加目标以构建参考

  <Target Name="ComputeProjectReference" Inputs="@(ProjectReference)" Outputs="%(ProjectReference.Identity)__Forced">
    <MSBuild Projects="@(ProjectReference)" Targets="%(ProjectReference.Targets)">
      <Output TaskParameter="TargetOutputs" ItemName="ResolvedProjectReferences"/>
    </MSBuild>
  </Target>

  <Target Name="AfterProjectReference"  AfterTargets="ComputeProjectReference">
    <CreateItem Include="@(ResolvedProjectReferences)">
      <Output TaskParameter="Include" ItemName="CopyFiles" />
    </CreateItem>

    <Copy SourceFiles="@(CopyFiles)" DestinationFolder="$(AssemblyName)\$(OutputPath)" SkipUnchangedFiles="false"  />

    <ItemGroup>
      <NewAssemblies Include="$(AssemblyName)\$(OutputPath)%(CopyFiles.FileName)%(CopyFiles.Extension)" />
    </ItemGroup>

  </Target>

不幸的是,MSBuild任务不将引用作为参数。我建议创建代表每个项目所需的itemGroups。

之类的东西   
  <ItemGroup>
    <CompileA Include="ConsProject\Program.cs" />
    <CompileA Include="ConsProject\Properties\AssemblyInfo.cs" />
    <CompileA Include="ConsProject\Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
      <DependentUpon>Settings.settings</DependentUpon>
    </CompileA>
  </ItemGroup>

  <ItemGroup>
    <CompileB Include="OtherProject\Program.cs" />
    <CompileB Include="OtherProject\Properties\AssemblyInfo.cs" />
    <CompileB Include="OtherProject\Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
      <DependentUpon>Settings.settings</DependentUpon>
    </CompileB>
  </ItemGroup>

创建一个目标,用一次编译的引用构建项目

  <!--Build Process-->
  <Target Name="Build" DependsOnTargets="ComputeProjectReference" >
    <Csc Sources="@(CompileA)" References="@(NewAssemblies)" TargetType="exe" OutputAssembly="$(AssemblyName)\$(OutputPath)\$(AssemblyName).exe" />

    <Csc Sources="@(CompileB)" References="@(NewAssemblies)" TargetType="exe" OutputAssembly="$(AssemblyName)\$(OutputPath)\$(AssemblyName).exe" />

  </Target>

答案 1 :(得分:1)

我弄清楚为什么要为每个解决方案重新编译共享项目。我们在每个项目中都有一个后期构建步骤,代码对目标文件进行签名。在每次编译项目之后,.dll文件比.pdb文件更新,因此它重新编译项目。我通过使用/ v:d开关进行详细日志记录,然后在输出中搜索“完全”来找出每次完全构建项目的原因。

答案 2 :(得分:0)

Visual Studio可能会使重建有些困难,因为它具有带有自定义启发式功能的“最新更新检查器”。您可以通过在注册表项中启用快速更新检查器的详细信息来找出为什么要重建项目:

Visual Studio 2017 (必须正在运行)[2]

New-ItemProperty              `
 -Name U2DCheckVerbosity      `
 -PropertyType DWORD -Value 1 `
 -Path HKCU:\Software\Microsoft\VisualStudio\15.0\General -Force

Visual Studio 2015

New-ItemProperty              `
 -Name U2DCheckVerbosity      `
 -PropertyType DWORD -Value 1 `
 -Path HKCU:\Software\Microsoft\VisualStudio\14.0\General -Force

您应该能够在构建日志消息中看到

  

项目“ Caliburn.Micro.Silverlight.Extensions”不是最新的。项目项“ C:\ dev \ projects \ Caliburn.Micro.Silverlight.Extensions \ NavigationBootstrapperSample.cs.pp”的“复制到输出目录”属性设置为“始终复制”。

[1] https://blogs.msdn.microsoft.com/kirillosenkov/2014/08/04/how-to-investigate-rebuilding-in-visual-studio-when-nothing-has-changed/

[2] https://visualstudioextensions.vlasovstudio.com/2017/06/29/changing-visual-studio-2017-private-registry-settings/ Visual Studio 2017使用私有注册表配置单元