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


 



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


 



  1. 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 –




    1. 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.
    2. The TargetOutputs item does not include the PDB files and other output configuration files for different type of projects.



  1. 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 –  



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



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



  1. Desktop build will not get impacted
  2. If the OutputFolder attribute is not specified, then we revert back to the original behavior
  3. User does not need to make any modifications to the individual .csproj files (big +)

 Disadvantages of this approach



  1. I am not sure of the impact on project to project reference.  
  2. You will get a (dummy) entry under compile steps in report for building tfsbuild.proj. You can just ignore it.
  3. 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 -)
  4. Not tested the test task. User might need to specify (hardcode) the correct value of SearchPathRoot property. (big -)

Tested scenarios



  1. Desktop clean/build/rebuild without specifying the OutputFolder attribute
  2. Desktop clean/build/rebuild with OutputFolder attribute defined
  3. End to end build with OutputFolder attribute for all solutions
  4. End to end build with OutputFolder attribute for some solutions

 


Comments (9)

  1. Shrish Jain says:

    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?

  2. Please refer the file  Microsoft.teamfoundation.build.targets for all such macros

  3. Alex Bögli says:

    "… We are working on it". Are there any news?

  4. Gautam Goenka posted an article on this topic way back on April 20, 2006. It included a targets file

  5. xsignal says:

    This did not work for me on OrcasBeta1TFS

  6. I search the net for a while for this problem: We using tfs build to perform a daily build. The following

  7. こんにちは! フォーラム オペレーターの服部清次です。 前回の更新から少し時間が経ち、 あっという間に2月も後半に入 ってしまいましたが、皆さん、いかがお過ごしですか? 今日は、久しぶりに、 MSDN