views:

1712

answers:

2

We recently upgraded from MSBuild 2005 to 2008. Since then MSBuild stops on the first error when building a solution. This wasn't the case in 2005. Is there a way to get the old behavior?

EDIT: We call MSBuild form the command line:

MSBuild.exe xyz.sln /p:Platform=Win32 /p:Configuration=Debug
+1  A: 
<MSBuild Projects="@(Solution)" ContinueOnError="false" StopOnFirstFailure="true"></MSBuild>

You have to change this on the script

Mariano
This wouldn't help because I only want to build one solution and try to avoid that MSBuild stops building it on occurence of the first error in one of the solution's projects. Your suggestion is good if I had several solutions.
rstevens
+1  A: 

I've got a kind of solution which is a little bit complex but it works:

When calling MSBuild with a solution file it internally generates a project file from that solution and build that project file. When setting the environment variable msbuildemitsolution to 1 it outputs that project file onto the hard disk named like the solution file but followed with .proj. In addition it always generates a .cache file that prevents it from regenerating the project file all the time. So what I do first is:

IF EXIST xyz.sln.proj DEL xyz.sln.proj
IF EXIST xyz.sln.cache DEL xyz.sln.cache
SET msbuildemitsolution=1
MSBuild.exe xyz-sln /t:_xxxxx_ /noconsolelogger

Where the target xxxx should NOT exist. MSBuild then generates a xyz.sln.proj and outputs many errors because of the missing target. I ignore the errors because what I wanted was the project file. Actually I do the above stuff within a C# program but for easier understanding I chose BAT syntax here.

The xyz.sln.proj consists of many targets: "Build", "Clean", "Rebuild" and "Publish" and "", ":Clean", ":Rebuild", ":Publish", ""... What I'm interested in are only the targets "Build", "Rebuild" and "Clean". Those targets consist of several MSBuild tasks that build sets of csproj files. Those sets are called BuildLevelX (where X is a number). For C++ projects the Build/Rebuild/Clean targets contain CallTarget tasks that directly call the tasks. A snippet from my file:

<Target Name="Build" Condition="'$(CurrentSolutionConfigurationContents)' != ''" Outputs="@(CollectedBuildOutput)">
  <MSBuild Condition="@(BuildLevel0) != ''" Projects="@(BuildLevel0)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
    <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
  </MSBuild>
  <Message Text="The project &quot;%(SkipLevel0.Identity)&quot; is not selected for building in solution configuration &quot;$(Configuration)|$(Platform)&quot;." Condition="@(SkipLevel0) != ''" />
  <Warning Text="The project configuration for project &quot;%(MissingConfigLevel0.Identity)&quot; was not specified in the solution file for the solution configuration &quot;$(Configuration)|$(Platform)&quot;." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel0) != ''" />
  <MSBuild Condition="@(BuildLevel1) != ''" Projects="@(BuildLevel1)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
    <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
  </MSBuild>
  <Message Text="The project &quot;%(SkipLevel1.Identity)&quot; is not selected for building in solution configuration &quot;$(Configuration)|$(Platform)&quot;." Condition="@(SkipLevel1) != ''" />
  <Warning Text="The project configuration for project &quot;%(MissingConfigLevel1.Identity)&quot; was not specified in the solution file for the solution configuration &quot;$(Configuration)|$(Platform)&quot;." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel1) != ''" />
  <CallTarget Targets="SomeLib" RunEachTargetSeparately="true" ContinueOnError="true" />
  <MSBuild Condition="@(BuildLevel2) != ''" Projects="@(BuildLevel2)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
    <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
  </MSBuild>
  <Message Text="The project &quot;%(SkipLevel2.Identity)&quot; is not selected for building in solution configuration &quot;$(Configuration)|$(Platform)&quot;." Condition="@(SkipLevel2) != ''" />
  <Warning Text="The project configuration for project &quot;%(MissingConfigLevel2.Identity)&quot; was not specified in the solution file for the solution configuration &quot;$(Configuration)|$(Platform)&quot;." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel2) != ''" />
  <CallTarget Targets="SomeProgram" RunEachTargetSeparately="true" ContinueOnError="true" />
  <MSBuild Condition="@(BuildLevel3) != ''" Projects="@(BuildLevel3)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
    <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
  </MSBuild>
  <Message Text="The project &quot;%(SkipLevel3.Identity)&quot; is not selected for building in solution configuration &quot;$(Configuration)|$(Platform)&quot;." Condition="@(SkipLevel3) != ''" />
  <Warning Text="The project configuration for project &quot;%(MissingConfigLevel3.Identity)&quot; was not specified in the solution file for the solution configuration &quot;$(Configuration)|$(Platform)&quot;." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel3) != ''" />
  <MSBuild Condition="@(BuildLevel4) != ''" Projects="@(BuildLevel4)" Properties="Configuration=%(Configuration); Platform=%(Platform); BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" ToolsVersion="$(ProjectToolsVersion)" BuildInParallel="true" UnloadProjectsOnCompletion="$(UnloadProjectsOnCompletion)" UseResultsCache="$(UseResultsCache)" ContinueOnError="true">
    <Output TaskParameter="TargetOutputs" ItemName="CollectedBuildOutput" />
  </MSBuild>
  <Message Text="The project &quot;%(SkipLevel4.Identity)&quot; is not selected for building in solution configuration &quot;$(Configuration)|$(Platform)&quot;." Condition="@(SkipLevel4) != ''" />
  <Warning Text="The project configuration for project &quot;%(MissingConfigLevel4.Identity)&quot; was not specified in the solution file for the solution configuration &quot;$(Configuration)|$(Platform)&quot;." Code="MSB4121" HelpKeyword="MSBuild.SolutionProjectConfigurationMissing" Condition="@(MissingConfigLevel4) != ''" />
</Target>

I load the proj file and add ContinueOnError="true" to all MSBuild and CallTarget tasks in the Build/Rebuild/Clean target:

XmlDocument msBuildProject = new XmlDocument();
msBuildProject.Load(Tools.getFullPath(m_strBaseDir, strSolutionProjFile));
foreach (XmlNode nodeL0 in msBuildProject.ChildNodes)
{
  XmlElement elementL0 = nodeL0 as XmlElement;
  if ((elementL0 != null) && (String.CompareOrdinal(nodeL0.Name, "Project") == 0))
  {
    foreach (XmlNode nodeL1 in elementL0.ChildNodes)
    {
      XmlElement elementL1 = nodeL1 as XmlElement;
      if ((elementL1 != null) && (String.CompareOrdinal(nodeL1.Name, "Target") == 0))
      {
        if ((String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Build") == 0) ||
            (String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Rebuild") == 0) ||
            (String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Clean") == 0) ||
            (String.CompareOrdinal(elementL1.Attributes["Name"].Value, "Publish") == 0))
        {
          foreach (XmlNode nodeL2 in elementL1.ChildNodes)
          {
            XmlElement elementL2 = nodeL2 as XmlElement;
            if ((elementL2 != null) &&
                ((String.CompareOrdinal(nodeL2.Name, "MSBuild") == 0) ||
                 (String.CompareOrdinal(nodeL2.Name, "CallTarget") == 0)))
            {
              elementL2.SetAttribute("ContinueOnError", "true");
            }
          }
        }
      }
    }
  }
}
msBuildProject.Save(Tools.getFullPath(m_strBaseDir, strSolutionProjFile));

After that I call MSBuild with the configuration.

This works fine but because it is not very easy I will never mark this as an answer to my question :-)

rstevens