Redirecting the copy of output assemblies for individual solutions to specified subfolders at drop site in Team Build
Team Build overrides the output directories that are specified in the individual project files, and thus places all build output at $(BinariesRoot)\$(Platfom)\$(Configuration)\
- Is there a way disable copying the assemblies at drop site?
Yes, you need to set the SkipDropBuild property to true inside your tfsbuild.proj file.
- Disable override behavior and have team Build use the relative output paths specified in each project properties?
No it is not possible now. We are working on it.
Unfortunately Team Build can not use the relative output paths specified in each project properties. We wanted to use TargetOutputs item which captures the relative path of output assembly (based on project settings). We can not use it because –
-
The item is populated only when we call MSbuild on .XXPROJ files. It does not get initialized when we call MSbuild on .SLN files. In Team Build basic unit of building is .SLN.
The TargetOutputs item does not include the PDB files and other output configuration files for different type of projects.
- Specify override for individual projects during the build without any impact on desktop scenario?
There is no easy way to do it but I do have this workaround –
Expected actions from the user -
- Override the core compile target and core clean target. Just past the following code in your tfsbuild.proj (towards the end , just before </project> tag). Note that you should not make modifications to Microsoft.Teamfoundation.Build.targets file.
<Target Name="CoreClean"
DependsOnTargets="$(CoreCleanDependsOn)"
Condition=" '$(SkipClean)'!='true' ">
<!-- Clean for desktop build -->
<MSBuild
Condition="'$(IsDesktopBuild)'=='true'"
Projects="$(MSBuildProjectFile)"
Targets="RunCoreCleanWithConfiguration"
Properties="RunCodeAnalysis=$(RunCodeAnalysis); BinariesRoot=$(BinariesRoot);FxCopDir=$(FxCopDir);Platform=%(ConfigurationToBuild.PlatformToBuild);Flavor=%(ConfigurationToBuild.FlavorToBuild); " />
<!-- Clean SolutionRoot only for end to end build -->
<RemoveDir
Condition="Exists('$(SolutionRoot)') and '$(IsDesktopBuild)'!='true'"
Directories="$(SolutionRoot)" />
<RemoveDir
Condition="Exists('$(BinariesRoot)') and '$(IsDesktopBuild)'!='true'"
Directories="$(BinariesRoot)" />
<RemoveDir
Condition="Exists('$(TestResultsRoot)') and '$(IsDesktopBuild)'!='true'"
Directories="$(TestResultsRoot)" />
</Target>
<Target Name="RunCoreCleanWithConfiguration" >
<!-- OutDirForClean for not Any CPU -->
<CreateItem
Condition=" '$(Platform)'!='Any CPU' "
Include="$(BinariesRoot)\$(Platform)\$(Flavor)\" >
<Output TaskParameter="Include" ItemName="OutDirForClean" />
</CreateItem>
<!-- OutDirForClean for Any CPU -->
<CreateItem
Condition=" '$(Platform)'=='Any CPU' "
Include="$(BinariesRoot)\$(Flavor)\" >
<Output TaskParameter="Include" ItemName="OutDirForClean" />
</CreateItem>
<!-- OutDir - to ensure we have absolute path as property -->
<CreateProperty Value="%(OutDirForClean.FullPath)" >
<Output TaskParameter="Value" PropertyName="OutDir" />
</CreateProperty>
<!-- Call MSBuild /t:Clean for desktop build -->
<MSBuild
Projects="@(SolutionToBuild)"
Properties="Configuration=$(Flavor);Platform=$(Platform);RunCodeAnalysis=$(RunCodeAnalysis);SkipInvalidConfigurations=true;FxCopDir=$(FxCopDir);OutDir=$(OutDir)%(SolutionToBuild.OutputFolder)\"
Targets="Clean" />
</Target>
<Target Name="CoreCompile"
DependsOnTargets="$(CoreCompileDependsOn)">
<MakeDir
Directories="$(BinariesRoot)"
Condition="!Exists('$(BinariesRoot)')" />
<TeamBuildMessage
Tag="Configuration"
Condition=" '$(IsDesktopBuild)'!='true' "
Value="%(ConfigurationToBuild.FlavorToBuild)" />
<TeamBuildMessage
Tag="Platform"
Condition=" '$(IsDesktopBuild)'!='true' "
Value="%(ConfigurationToBuild.PlatformToBuild)" />
<!-- Need proper location of build type otherwise logger fail (file not in enlistment)-->
<MSBuild
Condition="'$(IsDesktopBuild)'!='true' "
Projects="$(SolutionRoot)\TeamBuildTypes\$(BuildType)\TfsBuild.proj"
Targets="RunCoreCompileWithConfiguration"
Properties="Platform=%(ConfigurationToBuild.PlatformToBuild);Flavor=%(ConfigurationToBuild.FlavorToBuild);RunCodeAnalysis=$(RunCodeAnalysis);BinariesRoot=$(BinariesRoot);FxCopDir=$(FxCopDir);TeamBuildConstants=$(TeamBuildConstants);SolutionRoot=$(SolutionRoot)" />
<!-- Destop build, need this because $(Buildtype) not defined in desktop scenario-->
<MSBuild
Condition="'$(IsDesktopBuild)'=='true' "
Projects="$(MSBuildProjectFile)"
Targets="RunCoreCompileWithConfiguration"
Properties="Platform=%(ConfigurationToBuild.PlatformToBuild);Flavor=%(ConfigurationToBuild.FlavorToBuild);RunCodeAnalysis=$(RunCodeAnalysis);BinariesRoot=$(BinariesRoot);FxCopDir=$(FxCopDir);TeamBuildConstants=$(TeamBuildConstants);SolutionRoot=$(SolutionRoot)" />
<OnError ExecuteTargets="OnBuildBreak;" />
</Target>
<Target Name="RunCoreCompileWithConfiguration" >
<!-- OutDirForCompile for not Any CPU -->
<CreateItem
Condition=" '$(Platform)'!='Any CPU' "
Include="$(BinariesRoot)\$(Platform)\$(Flavor)\" >
<Output TaskParameter="Include" ItemName="OutDirForCompile" />
</CreateItem>
<!-- OutDirForCompile for Any CPU -->
<CreateItem
Condition=" '$(Platform)'=='Any CPU' "
Include="$(BinariesRoot)\$(Flavor)\" >
<Output TaskParameter="Include" ItemName="OutDirForCompile" />
</CreateItem>
<!-- OutDir property - This is to ensure we have absolute path as property -->
<CreateProperty Value="%(OutDirForCompile.FullPath)" >
<Output TaskParameter="Value" PropertyName="OutDir" />
</CreateProperty>
<!-- First part of VCOverride file -->
<CreateProperty Value="%3C?xml version=%221.0%22?%3E%0D%0A%3CVisualStudioPropertySheet ProjectType=%22Visual C++%22 Version=%228.00%22 Name=%22Team Build Overrides%22 OutputDirectory=%22$(OutDir)%22%3E%0D%0A" >
<Output TaskParameter="Value"
PropertyName="VCOverridesString1"/>
</CreateProperty>
<!-- Third part of VCOverride file -->
<CreateProperty Value="%3C/VisualStudioPropertySheet%3E" >
<Output TaskParameter="Value"
PropertyName="VCOverridesString3"/>
</CreateProperty>
<!-- RunCodeAnalysis option -->
<CreateProperty
Condition=" '$(RunCodeAnalysis)'=='Always' "
Value="RunCodeAnalysis=true" >
<Output TaskParameter="Value"
PropertyName="CodeAnalysisOption" />
</CreateProperty>
<!— 2nd part of VCOverride file when RunCodeAnalysis is always -->
<CreateProperty
Condition=" '$(RunCodeAnalysis)'=='Always' "
Value="%09%3CTool Name=%22VCCLCompilerTool%22 EnablePREfast=%22true%22 /%3E%0D%0A%09%3CTool Name=%22VCFxCopTool%22 EnableFxCop=%22true%22 /%3E%0D%0A" >
<Output TaskParameter="Value"
PropertyName="VCOverridesString2"/>
</CreateProperty>
<CreateProperty
Condition=" '$(RunCodeAnalysis)'=='Never' "
Value="RunCodeAnalysis=false" >
<Output TaskParameter="Value"
PropertyName="CodeAnalysisOption" />
</CreateProperty>
<!-- Second part of VCOverride file when RunCodeAnalysis is never -->
<CreateProperty
Condition=" '$(RunCodeAnalysis)'=='Never' "
Value="%09%3CTool Name=%22VCCLCompilerTool%22 EnablePREfast=%22false%22 /%3E%0D%0A%09%3CTool Name=%22VCFxCopTool%22 EnableFxCop=%22false%22 /%3E%0D%0A" >
<Output TaskParameter="Value"
PropertyName="VCOverridesString2"/>
</CreateProperty>
<!-- ReferencePath option -->
<CreateProperty
Condition=" '@(AdditionalReferencePath)'!='' "
Value="$(OutDir);@(AdditionalReferencePath)" >
<Output TaskParameter="Value" PropertyName="ReferencePath" />
</CreateProperty>
<CreateProperty
Condition=" '@(AdditionalReferencePath)'=='' "
Value="$(OutDir)" >
<Output TaskParameter="Value" PropertyName="ReferencePath" />
</CreateProperty>
<!-- Generate VCOverride file for C++ projects -->
<WriteLinesToFile
File="TFSBuild.vsprops"
Lines="$(VCOverridesString1)$(VCOverridesString2)$(AdditionalVCOverrides)$(VCOverridesString3)"
Overwrite="true" />
<!-- Build using MSBuild task -->
<MSBuild
Condition=" '@(SolutionToBuild)'!='' "
Projects="@(SolutionToBuild)"
Properties="Configuration=$(Flavor);Platform=$(Platform);SkipInvalidConfigurations=true;VCBuildOverride=$(MSBuildProjectDirectory)\TFSBuild.vsprops;FxCopDir=$(FxCopDir);OutDir=$(OutDir)%(SolutionToBuild.OutputFolder)\;ReferencePath=$(ReferencePath);TeamBuildConstants=$(TeamBuildConstants);$(CodeAnalysisOption)"
Targets="Build" />
<!-- Specify SolutionToPublish ItemGroup if you have ClickOnce based solutions or projects that you want to publish. The task below will generate manifest and deployment package. -->
<MSBuild
Condition=" '@(SolutionToPublish)'!='' "
Projects="@(SolutionToPublish)"
Properties="Configuration=$(Flavor);Platform=$(Platform);SkipInvalidConfigurations=true;VCBuildOverride=$(MSBuildProjectDirectory)\TFSBuild.vsprops;FxCopDir=$(FxCopDir);OutDir=$(OutDir)%(SolutionToPublish.OutputFolder)\;PublishDir=$(OutDir)%(SolutionToPublish.OutputFolder)\;ReferencePath=$(ReferencePath);TeamBuildConstants=$(TeamBuildConstants);$(CodeAnalysisOption)"
Targets="Publish" />
</Target>
- In the build type file you need to make the following changes –
<ItemGroup>
<SolutionToBuild Include="$(SolutionRoot)\ClassLibrary1\ClassLibrary1.sln">
< OutputFolder > Lib</OutputFolder>
</SolutionToBuild>
<SolutionToBuild Include="$(SolutionRoot)\ConsoleApplication1\ConsoleApplication1.sln">
< OutputFolder > App</OutputFolder>
</SolutionToBuild>
</ItemGroup>
Please note the OutputFolder attribute will point to the sub folder under BinariesRoot\<platform>\<configuration>. For example in the above scenario we are interested in building for AnyCPU|Debug, then the output assemblies will be @ $(BinariesRoot)\Debug\Lib\Classlibrary1.dll, $(BinariesRoot)\Debug\App\ClassApplication1.exe.
It is not advisable to change the structure to BinariesRoot\ <subfolder> \<platform>\<configuration>.
Advantages of this approach
Desktop build will not get impacted
If the OutputFolder attribute is not specified, then we revert back to the original behavior
User does not need to make any modifications to the individual .csproj files (big +)
Disadvantages of this approach
I am not sure of the impact on project to project reference.
You will get a (dummy) entry under compile steps in report for building tfsbuild.proj. You can just ignore it.
Solution will not work for unmanaged projects (using VCBuild.exe) that uses overrides file. The reason is that we generate the overrides file once and then pass it for all solutions. We can not do task batching while generating the overrides file (because it will impact the order in which solutions will be build) (big -)
Not tested the test task. User might need to specify (hardcode) the correct value of SearchPathRoot property. (big -)
Tested scenarios
- Desktop clean/build/rebuild without specifying the OutputFolder attribute
- Desktop clean/build/rebuild with OutputFolder attribute defined
- End to end build with OutputFolder attribute for all solutions
- End to end build with OutputFolder attribute for some solutions
Comments
Anonymous
April 06, 2006
I see you using $(BinariesRoot)- I would like to know how they are defined- Any documentation where I can find other macros like this one?Anonymous
April 06, 2006
Please refer the file Microsoft.teamfoundation.build.targets for all such macrosAnonymous
July 03, 2006
"... We are working on it". Are there any news?Anonymous
March 19, 2007
Gautam Goenka posted an article on this topic way back on April 20, 2006. It included a targets fileAnonymous
July 06, 2007
This did not work for me on OrcasBeta1TFSAnonymous
March 04, 2008
I search the net for a while for this problem: We using tfs build to perform a daily build. The followingAnonymous
September 12, 2008
PingBack from http://alipka.wordpress.com/2006/03/19/tfsmsbuild-caveats/Anonymous
February 16, 2009
こんにちは! フォーラム オペレーターの服部清次です。 前回の更新から少し時間が経ち、 あっという間に2月も後半に入 ってしまいましたが、皆さん、いかがお過ごしですか? 今日は、久しぶりに、 MSDNAnonymous
June 09, 2009
PingBack from http://weakbladder.info/story.php?id=5084