Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In certain cases, errors in one target don't stop a subsequent target from running and generating errors #2116

Closed
dsplaisted opened this issue May 19, 2017 · 1 comment · Fixed by #2133
Assignees
Labels
Milestone

Comments

@dsplaisted
Copy link
Member

In the .NET SDK, we have targets that run early on in the build process to verify things like whether the target framework is valid or not. If we generate errors in those targets, we would expect targets that depend on the target that is generating an error not to run and not to generate errors. However, this is not what is happening. This means that the error that specifies the root cause of the problem can be lost amidst the many subsequent errors that might be generated.

See dotnet/sdk#798 for more context.

Here are two minimal repros of the issue:

GetReferenceAssemblyPaths error

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
  
  <Target Name="_CheckForUnsupportedTargetFramework"
      BeforeTargets="_CheckForInvalidConfigurationAndPlatform;_CheckCompileDesignTimePrerequisite;GetFrameworkPaths;GetReferenceAssemblyPaths;GenerateBuildRuntimeConfigurationFiles">
    <Error Text="Error in _CheckForUnsupportedTargetFramework" />
  </Target>

  <Target Name="_CheckForInvalidConfigurationAndPlatform" BeforeTargets="$(BuildDependsOn);Build" />
  
  <PropertyGroup>
    <BuildDependsOn>
      EntityDeploy;
      CoreBuild;
    </BuildDependsOn>
  </PropertyGroup>
  
  <Target Name="Build" DependsOnTargets="$(BuildDependsOn)" Returns="$(TargetPath)" />

  <Target Name="CoreBuild" DependsOnTargets="PrepareForBuild;GenerateBuildRuntimeConfigurationFiles"/>

  <Target Name="PrepareForBuild" DependsOnTargets="GetReferenceAssemblyPaths"/>
  
  <Target Name="GetReferenceAssemblyPaths">
    <Error Text="GetReferenceAssemblyPaths Error" />
  </Target>

  <Target Name="EntityDeploy" Condition="'@(EntityDeploy)' != ''" />
</Project>

In this repro, I would hope that the error in _CheckForUnsupportedTargetFramework would prevent subsequent targets from being run. Something about the EntityDeploy target being added to the start of BuildDependsOn, and possibly the fact that BuildDependsOn is being used both in Build as DependsOnTargets and in _CheckForInvalidConfigurationAndPlatform as BeforeTargets is causing GetReferenceAssemblyPaths to run even after a previous target has failed.

GenerateBuildRuntimeConfigurationFiles error

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
  
  <Target Name="_CheckForUnsupportedTargetFramework"
      BeforeTargets="_CheckForInvalidConfigurationAndPlatform;_CheckCompileDesignTimePrerequisite;GetFrameworkPaths;GetReferenceAssemblyPaths;GenerateBuildRuntimeConfigurationFiles">
    <Error Text="Error in _CheckForUnsupportedTargetFramework" />
  </Target>

  <Target Name="_CheckForInvalidConfigurationAndPlatform" BeforeTargets="$(BuildDependsOn);Build" />
  
  <PropertyGroup>
    <BuildDependsOn>
      CoreBuild;
    </BuildDependsOn>
  </PropertyGroup>
  
  <Target Name="Build" DependsOnTargets="$(BuildDependsOn)" Returns="$(TargetPath)" />

  <Target Name="CoreBuild" DependsOnTargets="PrepareForBuild;GenerateBuildRuntimeConfigurationFiles">
    <OnError ExecuteTargets="_CleanRecordFileWrites" />
  </Target>

  <Target Name="PrepareForBuild" DependsOnTargets="GetReferenceAssemblyPaths"/>
  
  <Target Name="GetReferenceAssemblyPaths">
    
  </Target>

  <Target Name="_CheckForCompileOutputs"/>
  <Target Name="_CleanGetCurrentAndPriorFileWrites" DependsOnTargets="_CheckForCompileOutputs" />
  <Target Name="_CleanRecordFileWrites" DependsOnTargets="_CleanGetCurrentAndPriorFileWrites"/>

  <Target Name="GenerateBuildRuntimeConfigurationFiles" BeforeTargets="_CheckForCompileOutputs">
    <Error Text="GenerateBuildRuntimeConfigurationFiles Error" />
  </Target>
  
</Project>

This is more straightforward. When I run this I'd expect to only get the error from _CheckForUnsupportedTargetFramework. However, I also get the error from GenerateBuildRuntimeConfigurationFiles. It looks like the OnError task in CoreBuild is causing _CleanRecordFileWrites and its dependencies to run after an error is encountered. I'm not sure exactly how to fix this though.

@AndyGerlicher
Copy link
Contributor

AndyGerlicher commented May 22, 2017

<Project>
  <Target Name="Build" DependsOnTargets="ProduceError1;ProduceError2" />

  <Target Name="ProduceError1" Condition="false" />

  <Target Name="ProduceError2">
    <Error Text="Error2" />
  </Target>

  <Target Name="_Error1" BeforeTargets="ProduceError1">
    <Error Text="Error1" />
  </Target>

</Project>

Haven't looked into what to do about it yet, but here's a more minimal repro. The issue here is the condition. Since the target ProduceError1 never actually runs the TargetBuilder ends up pushing a Dependencies state to the _targetsToBuild stack which finds _Error1 and runs it. If ProduceError1 did run, it correctly doesn't try to find the dependencies or run them.

AndyGerlicher added a commit to AndyGerlicher/msbuild that referenced this issue May 25, 2017
This issue occurs when two targets are scheduled to be built (e.g.
ProduceError1 and ProduceError2) and the condition of the first target
causes it to not execute and a dependent target
(BeforeTargets='ProduceError1') fails. In this example, ProduceError2
still executes.

Fixes dotnet#2116
AndyGerlicher added a commit to AndyGerlicher/msbuild that referenced this issue May 25, 2017
This issue occurs when two targets are scheduled to be built (e.g.
ProduceError1 and ProduceError2) and the condition of the first target
causes it to not execute and a dependent target
(BeforeTargets='ProduceError1') fails. In this example, ProduceError2
still executes.

Fixes dotnet#2116
AndyGerlicher added a commit to AndyGerlicher/msbuild that referenced this issue May 25, 2017
This issue occurs when two targets are scheduled to be built (e.g.
ProduceError1 and ProduceError2) and the condition of the first target
prevents it from executing and a dependent target
(BeforeTargets='ProduceError1') fails. This change prevents
ProduceError2 from executing by marking the parent of the failure
(ProduceError1) with the Stop WorkUnitActionCode.

Fixes dotnet#2116

Update
AndyGerlicher added a commit that referenced this issue May 25, 2017
Fixes an issue which occurs when two targets are scheduled to be built 
(e.g. ProduceError1 and ProduceError2), the condition of the first target
prevents it from executing, and a dependent target
(BeforeTargets='ProduceError1') fails. This change prevents
ProduceError2 from executing by marking the parent of the failure
(ProduceError1) with the Stop WorkUnitActionCode.

Fixes #2116
@AR-May AR-May added the triaged label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants