Why is MSBuild restoring collaborative projects?

I try to speed up the assembly of a set of solutions by compiling collaborative projects only once. This is a simplified description of my problem.

I have two solutions - one.sln and two.sln. Both of them include the shared project shared.csproj. I open two solutions in Visual Studio, clear them, and then create one.sln and then create two.sln. When build.sln is built, shared.dll is NOT regenerated, as I expect this behavior.

To automate this process, I created the msbuild.proj file (below). When I call msbuild in a .proj file, shared.dll is recompiled for the BOTH solutions. What am I doing wrong?

<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> 
+5
source share
2 answers

IIRC, the reason the link is compiled twice, is because it is declared as a reference project in both solutions. Thus, both will call the assembly object a reference. This is how I understand it.

Create a group of elements for a reference project

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

Add target to create link

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

Unfortunately, the MSBuild task does not accept links as a parameter. I suggest creating itemGroups that represent each project. sort of

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

And create a goal to build projects with lists compiled once

  <!--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> 
+3
source

I understood why the collaborative projects were recompiled for each solution. In each project, we have a build step that signs the target file. After each previous compilation of the project, the .dll file is newer than the .pdb file, so it recompiles the project. I found this by using the / v: d switch for verbose logging, and then doing a “full” search on the output to find out why the projects were built completely every time.

+1
source

All Articles