Unable to call a target from overidden CoreCompile
Hi,
I would like to perform a specific target just before each solution is compiled. Unfortunatly, team build performs a build including all solution in an atomic MSBuild call. To correct this behavior, I tought I could overide the default CoreCompile with my own version, in order to call a private target just before each solution is built.
However, I can't get CoreCompile to call my target. Wondering what is wrong, I tried overloading CoreClean... and it worked beautifully!
Questions:
1. Is there anything special about CoreCompile?
2. What is the purpose of the constant _TEAM_BUILD_ defined just before CoreCompile?
3. Is there a better way to do what i am trying to do?
Finally, here is the .targets i've used to overload CoreCompile and CoreClean.
Regards,
Fred
<?xmlversion="1.0"encoding="utf-8"?>
<ProjectInitialTargets="CheckSettingsForEndToEndIteration"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ><!--
Clean for desktop build--><
TargetName="CoreClean"><
MSBuildProjects="$(MSBuildProjectFile)"Targets="Test"/></
Target><!--
Core compile--><
TargetName="CoreCompile"><
MSBuildProjects="$(MSBuildProjectFile)"Targets="Test"/></
Target><!--
Should be called by CoreClean and CoreCompile--><
TargetName="Test" ><
MessageText="Test ABC"/></
Target></
Project>
[5096 byte] By [
fredx21] at [2008-2-4]
Fredx,
1) There is nothing special about corecompile target. You should be able to overload it easily (similear way you are overloading the coreclean target).
Your fix calls the msbuild task on the same file with different target (test). Note that invoking msbuild task will create a seperate subprocess. The subprocess will not inherit the properties/items from the scope of parent process. This might result in invalid behavior/failures. An easier way would be to not call msbuild task but redefine standard targets in your tfsbuild.proj file. For example
in tfsbuild.proj file
<Target Name="CoreCompile"><Message Text="My custom task for compile"/></Target>
2) "_team_build_" is just teambuild specific constant that is passed to compile task. This is used to indicated that assemblies are generated by teambuild. They are just like other constants i.e DEBUG, TRACE, etc.
3) Better way to realize your scenario would be to modify your individual sln files (csproj) files and define the post build step. This will ensure that even when you are not building in teambuild the post build step will be executed.
I am afraid that there is not clean way in team build to enable your scenario (in case you do not want to execute the post build steps outside team build)
1. The subprocess not inheriting from the properties/items from the scope of its parent process might be a problem. However, from the result i get, its obvious that CoreClean and CoreCompile are not totally independant targets. Assuming that both targets are regular targets and that Team Build is not aware of any of them, there must be something in the default Microsoft.TeamFoundation.Build.targets that makes CoreCompile hang when calling an msbuild task on the same file with a different target.
3. Modifying the csproj/vcproj would be a valid alternative. However, modifying each project takes time, does not ensure that new projects are modified and is error prone. I tough I could use CallTarget but unfortunatly, it's not possible to pass parameters. There must be a way to divide an ItemGroup and call a target on each of them separetly.
Fred
Fred,
1) I will investigate the issue (corecompile target is hanging).
2) Modifying your proj files is easier. Anyways I will check alternatives and will let you know.
Manish,
I managed to find a solution for my problem. Instead of trying to call another target with a single solution, i've created a Task that is derived from Microsoft.Build.Tasks.MSBuild. In this task, the MSBuild.Execute() gets called one project at a time, allowing me to call some code in between compilations.
Here is my simple Task code.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
public class Export : Microsoft.Build.Tasks.MSBuild
{
protected bool BeforeCompile(String solutionPath)
{
return true;
}
protected bool AfterCompile(String solutionPath)
{
return true;
}
public override bool Execute()
{
ITaskItem[] projects = Projects;
bool bResult = true;
Projects = new ITaskItem[1];
foreach (ITaskItem project in projects) {
Projects[0] = project;
bResult = BeforeCompile(project.ToString());
if (!bResult) {
break;
}
Log.LogMessage("Compiling " + project.ToString());
bResult = base.Execute();
if (!bResult) {
break;
}
bResult = AfterCompile(project.ToString());
if (!bResult) {
break;
}
}
return bResult;
}
}
Even tought i've managed to do what i wanted to do, i will continue to wait for your input on the CoreCompile issue.
Regards,
Fred
Fred,
I was able to repro your failure. Note that when you override the core compile target and call msbuild with different target (i.e test),
<MSBuild
Projects="$(MSBuildProjectFile)" Targets="Test"/> Team build logger fails. This is because logger need to convert the proj/sln file (specified by Projects) local path to server path to show in the reports.
To convert the local path to server path, logger uses the workspace. In default scenario, since the workspace always maps to folder mapped to $(SolutionRoot) (where all your sln files are present), this is not an issue. However for your case, you refer to tfsbuild.proj file (specified by $(MSBuildProjectFile), present under BuildType folder) and the file does not belong to any workspace. Thus logger fails.
To make this work, you need to use the $(MSBuildProjectFile) present under $(SolutionRoot). i.e. change the definition to
<
MSBuild Projects="$(SolutionRoot)\TeamBuildTypes\$(BuildType)\tfsbuild.proj" Targets="Test"/>