msbuild not working properly with tfs 2010 and importet Microsoft.TeamFoundation.Build.targets - visual-studio

i'm stuck with extending my msbuild project file and tfs 2010. What i want to achieve is to automatically generate the documentation for my source code after the build. I searched the web and found out, that the file Microsoft.TeamFoundation.Build.targets defines a lot of customizable targets for either desktop- or team-build. One of them is the GenerateDocumentation-Target which i want to use. The Problem i have is, that despite i imported this file, the overloaded targets are not invoked by msbuild. The header of my vcxproj-File looks as follows:
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
after this i include the team build targets file with the statement
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets"/>
At the very end of this project file i tried to overload some targets as suggested in the TeamFoundation target file:
<Target Name="GenerateDocumentation">
<Message Text="GenerateDocumentation invoked" Importance="high"/>
</Target>
<Target Name="BeforeBuild">
<Message Text="BeforeBuild invoked" Importance="high" />
</Target>
<Target Name="AfterBuild">
<Message Text="AfterBuild invoked" Importance="high" />
</Target>
but except the AfterBuild-Target neither the GenerateDocumentation nor BeforeBuild target is called for a local build nor a build with the build server. Am i'm missing something? Is the DefaultTarget="Build" correct? I tried to change this to DefaultTarget="DesktopBuild" but then calling msbuild resulted in a variety of errors (MSB4018). In the project file the target file $(VCTargetsPath)\Microsoft.Cpp.targets is imported too. When removing this import, the GenerateDocumentation target is called, but not the other ones (including ResourceCompile which i need too). Can i use both of them somehow?
Thanks in advance...

what about adding this at the end of your build task...
<CallTarget Targets="GenerateDocumentation"></CallTarget>
</Target>

Related

Difficulty using <Import> to modularize a Visual Studio project file

I'm attempting to modularize a Visual Studio project file, but it's not working. This is for Visual Studio 2008 with .Net 3.5.
Shown below, the first example works, but the second one does not. How can I make it work..?
I'm new to this topic and probably missing something. I first became aware of it while reading a 3rd-party blog, and then found it in the documentation too. I've googled for more help, but there's too much information for me to find a relevant answer.
The main project file:
...
<!-- main project file -->
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Target Name="AfterBuild">
<Message Text="This is a message from the *.vbproj file."/> ... this works
</Target>
</Project>
...but if <Import> is used, with the same <Target> and <Message> in the imported file, it doesn't work. MSBuild seems to process everything correctly, but nothing happens...
The main project file:
...
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<Import Project="$(MSBuildProjectDirectory)\CustomBuildEvents.targets" /> ... new tag
<Target Name="AfterBuild">
<Message Text="This is a message from the *.vbproj file."/> ... this still works
</Target>
</Project>
The imported targets file:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild">
<Message Text="Hello from the imported file." Importance ="high"/> ... doesn't work
</Target>
</Project>
And the build output, with Verbosity set to Diagnostic:
### Halfway through the output, this is the only mention of the imported file. ###
None
CustomBuildEvents.targets ... custom file
My Project\Application.myapp
My Project\Settings.settings
### And then at the end, no mention of the imported file or its message. ###
Done building target "CoreBuild" in project "MsBuildCustomTargetTester.vbproj".
Target "AfterBuild" in file "C:\Visual Studio 2008\Solutions\MsBuildCustomTargetTester\MsBuildCustomTargetTester\MsBuildCustomTargetTester.vbproj":
Task "Message"
Hello from the *.vbproj file. ... message from main file
Done executing task "Message".
Done building target "AfterBuild" in project "MsBuildCustomTargetTester.vbproj".
Target "Build" in file "c:\WINDOWS\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets":
Building target "Build" completely.
No input files were specified.
Done building target "Build" in project "MsBuildCustomTargetTester.vbproj".
Done building project "MsBuildCustomTargetTester.vbproj".
Project Performance Summary:
109 ms C:\Visual Studio 2008\Solutions\MsBuildCustomTargetTester\MsBuildCustomTargetTester\MsBuildCustomTargetTester.vbproj 1 calls
The problem with AfterBuild is that it can only be defined once. So if you import it and then later in the project file define it again, the last definition wins and becomes the only definition.
To solve this you need to use the more advanced way to register events. Given that you are using Visual Studio 2008 (WHY?!), you need to use the more advanced syntax for your custom targets files:
<Project>
<!--
Redefines the original build order, includes the standard targets and
adds your new custom target to the end of the list.
-->
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomTarget
</BuildDependsOn>
</PropertyGroup>
<CustomTarget>
<!-- Imported after Build -->
<Message Text="Hello from the imported file." Importance ="high"/>
</CustomTarget>
</Project>
There are other ways to do this which were introduced in MsBuild 4 with the BeforeTargets and AfterTargets attributes on any target, but If I'm remembering correctly the above syntax should also work with the version of MsBuild that ships with Visual Studio 2008.
See also:
What is the difference between 'DependsOnTargets' and 'AfterTargets'?
https://blogs.msdn.microsoft.com/msbuild/2006/02/10/how-to-add-custom-process-at-specific-points-during-build-method-2/

Is it possible to run a post build event when the whole compilation finishes in Visual Studio 2013?

I have a solution with multiple projects and we use FxCop. We want to run it once the compilation requested finishes (it may be one project, a folder with several folders or the whole solution).
Is there a way of doing this? We currently do it per project but this has some drawbacks.
Yes, there is a way to do it by putting a file next to your solution file with a specific naming pattern: after.{Your solution name here}.sln.targets
<!--?xml version="1.0" encoding="utf-8"?-->
<project toolsversion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<target name="AtTheStart" beforetargets="Build">
<message text="GenerateCode target running" importance="high">
</message>
</target>
<target name="AtTheEnd" aftertargets="Build">
<message text="GenerateCode target running" importance="high">
</message>
</target>
</project>
But if you want to run FxCop effectively and have visualstudio installed, you can actually activate it during the build by including /p:RunCodeAnalysis=true or /p:RunCodeAnalysis=always on the call to MsBuild. This will run the configured ruleset file during the build. /p:CodeAnalysisRuleSet=PathTo.ruleset will let you specify a specific ruleset file.
The commandline will always overwrite the project's own configuration. And it will run in the most optimal way.
I would put the FxCop project set (with all the dll's in all your projects) and call it after all the projects are built in VS.

Visual Studio Express 2012 for Web - don't generate bin and obj folders

Can I turn off generating these folders on build? They contain some .dll, .pdb and other files I don't need. I'm just using Typescript compilation.
Yes, it is possible. I relied on the following nice overview on how to hijack a build process:
http://sedodream.com/2013/06/01/HijackingTheVisualStudioBuildProcess.aspx
Three main tricks:
1) project_name.csproj is the one you need to modify, it is XML MSBUILD file.
2) You cannot remove dependency from WebApplication.targets, you need to "deactivate" them as below.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
3) You have to implement general contract for clean/build/rebuild targets.
Mine looks like:
<Target Name="Build">
<Exec Command="call node_modules\.bin\tsc.cmd src/main.ts --out js/game.min.js > $(Temp)\tscout.txt" IgnoreExitCode="true" WorkingDirectory="$(SolutionDir)" />
<Exec Command="type $(Temp)\tscout.txt" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build">
</Target>
<Target Name="Clean">
<RemoveDir Directories="js">
</RemoveDir>
</Target>
You could create a New WebSite instead of New Project. That one should not create any binary output.

Can I build multiple configurations of a project within one solution configuration?

I would like to build the same project twice in the same solution configuration, varying some #define flags to toggle features. Both binaries will be deployed with different names.
The solutions that I know could work:
Add a solution configuration - But I will then need to build the solution twice, which I would prefer to avoid. Both project configurations will always be built.
Copy the project - But then I have the overhead of maintaining a new project when I only want to maintain a different configuration.
Batch build - I avoid using batch build as I use both devenv for local development and msbuild for continuous integration.
Any other ideas or suggestions?
Just figured out a way to do what you asked for. Create one msbuild file (I named mine multiple.proj) and add the script below.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Choose>
<When Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<ItemGroup>
<ProjectToBuild Include="$(MSBuildProjectName).csproj">
<Properties>Configuration=Release</Properties>
</ProjectToBuild>
</ItemGroup>
</When>
</Choose>
<Target Name="BeforeBuild">
<Message Text="Building configuration $(Configuration)..." />
</Target>
<Target Name="AfterBuild">
<MSBuild Projects="#(ProjectToBuild)"/>
</Target>
</Project>
</type>
</this>
Import the script on your projects (csproj or vbproj):
<Import Project="..\multiple.proj" />
This script tells msbuild to build again your project with another configuration as an AfterBuild event. I used Debug/Release to make the example, but you can easily change the script to support other configurations, or make the decision to build again based on other variables.
Be careful because you're running two builds at once, so build errors can be harder to understand.
Hope this helps.

Copy built assemblies (including PDB, .config and XML comment files) to folder post build

Is there a generic way I can get a post-build event to copy the built assembly, and any .config and any .xml comments files to a folder (usually solution relative) without having to write a post-build event on each project in a solution?
The goal is to have a folder that contains the last successful build of an entire solution.
It would be nice to use the same build solution over multiple solutions too, possibly enabling/ disabling certain projects (so don't copy unit tests etc).
Thanks,
Kieron
You can set common OutputPath to build all projects in Sln in one temp dir and copy required files to the latest build folder. In copy action you can set a filter to copy all dlls without "test" in its name.
msbuild.exe 1.sln /p:Configuration=Release;Platform=AnyCPU;OutputPath=..\latest-temp
There exists more complicated and more flexible solution. You can setup a hook for build process using CustomAfterMicrosoftCommonTargets. See this post for example.
Sample targets file can be like that:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
PublishToLatest
</BuildDependsOn>
</PropertyGroup>
<Target Name="PreparePublishingToLatest">
<PropertyGroup>
<TargetAssembly>$(TargetPath)</TargetAssembly>
<TargetAssemblyPdb>$(TargetDir)$(TargetName).pdb</TargetAssemblyPdb>
<TargetAssemblyXml>$(TargetDir)$(TargetName).xml</TargetAssemblyXml>
<TargetAssemblyConfig>$(TargetDir)$(TargetName).config</TargetAssemblyConfig>
<TargetAssemblyManifest>$(TargetDir)$(TargetName).manifest</TargetAssemblyManifest>
<IsTestAssembly>$(TargetName.ToUpper().Contains("TEST"))</IsTestAssembly>
</PropertyGroup>
<ItemGroup>
<PublishToLatestFiles Include="$(TargetAssembly)" Condition="Exists('$(TargetAssembly)')" />
<PublishToLatestFiles Include="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" />
<PublishToLatestFiles Include="$(TargetAssemblyXml)" Condition="Exists('$(TargetAssemblyXml)')" />
<PublishToLatestFiles Include="$(TargetAssemblyConfig)" Condition="Exists('$(TargetAssemblyConfig)')" />
<PublishToLatestFiles Include="$(TargetAssemblyManifest)" Condition="Exists('$(TargetAssemblyManifest)')" />
</ItemGroup>
</Target>
<Target Name="PublishToLatest"
Condition="Exists('$(LatestDir)') AND '$(IsTestAssembly)' == 'False' AND '#(PublishToLatestFiles)' != ''"
DependsOnTargets="PreparePublishingToLatest">
<Copy SourceFiles="#(PublishToLatestFiles)" DestinationFolder="$(LatestDir)" SkipUnchangedFiles="true" />
</Target>
</Project>
In that targets file you can specify any actions you want.
You can place it here "C:\Program Files\MSBuild\v4.0\Custom.After.Microsoft.Common.targets" or here "C:\Program Files\MSBuild\4.0\Microsoft.Common.targets\ImportAfter\PublishToLatest.targets".
And third variant is to add to every project you want to publish import of custom targets. See How to: Use the Same Target in Multiple Project Files

Resources