diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index 7645217f959..53c843c112a 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1048,7 +1048,7 @@ public enum BuildRequestDataFlags SkipNonexistentTargets = 16, ProvideSubsetOfStateAfterBuild = 32, IgnoreMissingEmptyAndInvalidImports = 64, - SkipNonexistentNonTopLevelTargets = 128, + SkipNonexistentNonEntryTargets = 128, FailOnUnresolvedSdk = 256, } public partial class BuildResult diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index a34525978b8..b1f8429b5cb 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1043,7 +1043,7 @@ public enum BuildRequestDataFlags SkipNonexistentTargets = 16, ProvideSubsetOfStateAfterBuild = 32, IgnoreMissingEmptyAndInvalidImports = 64, - SkipNonexistentNonTopLevelTargets = 128, + SkipNonexistentNonEntryTargets = 128, FailOnUnresolvedSdk = 256, } public partial class BuildResult diff --git a/src/Build/BackEnd/BuildManager/BuildRequestData.cs b/src/Build/BackEnd/BuildManager/BuildRequestData.cs index 18993b6cc1b..673ee5f0fdf 100644 --- a/src/Build/BackEnd/BuildManager/BuildRequestData.cs +++ b/src/Build/BackEnd/BuildManager/BuildRequestData.cs @@ -77,12 +77,12 @@ public enum BuildRequestDataFlags IgnoreMissingEmptyAndInvalidImports = 1 << 6, /// - /// When this flag is present, non top level target(s) in the build request will be skipped if those targets - /// are not defined in the Project to build. The build will still fail if a top lvel target does not exist. + /// When this flag is present, non entry target(s) in the build request will be skipped if those targets + /// are not defined in the Project to build. The build will still fail if an entry target does not exist. /// This only applies to this build request (if another target calls the "missing target" at any other point /// this will still result in an error). /// - SkipNonexistentNonTopLevelTargets = 1 << 7, + SkipNonexistentNonEntryTargets = 1 << 7, /// /// When this flag is present, an unresolved MSBuild project SDK will fail the build. This flag is used to diff --git a/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs index 3bd6f83b6e5..33486a859be 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs @@ -143,21 +143,24 @@ public async Task BuildTargets(ProjectLoggingContext loggingContext foreach (string targetName in targetNames) { var targetExists = _projectInstance.Targets.TryGetValue(targetName, out ProjectTargetInstance targetInstance); - // Ignore the missing target if: - // SkipNonexistentTargets is set - // -or- - // SkipNonexistentNonTopLevelTargets and the target is is not a top level target - if (!targetExists - && entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentTargets) - || entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentNonTopLevelTargets) && !entry.Request.Targets.Contains(targetName)) + + if (!targetExists) { - _projectLoggingContext.LogComment(Framework.MessageImportance.Low, - "TargetSkippedWhenSkipNonexistentTargets", targetName); - } - else - { - targets.Add(new TargetSpecification(targetName, targetExists ? targetInstance.Location : _projectInstance.ProjectFileLocation)); + // Ignore the missing target if: + // SkipNonexistentTargets is set + // -or- + // SkipNonexistentNonEntryTargets and the target is is not a top level target + if (entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentTargets) + || entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentNonEntryTargets) && !entry.Request.Targets.Contains(targetName)) + { + _projectLoggingContext.LogComment(Framework.MessageImportance.Low, + "TargetSkippedWhenSkipNonexistentTargets", targetName); + + continue; + } } + + targets.Add(new TargetSpecification(targetName, targetExists ? targetInstance.Location : _projectInstance.ProjectFileLocation)); } // Push targets onto the stack. This method will reverse their push order so that they diff --git a/src/MSBuild.UnitTests/XMake_Tests.cs b/src/MSBuild.UnitTests/XMake_Tests.cs index 8723b61b5bb..e014f5652e3 100644 --- a/src/MSBuild.UnitTests/XMake_Tests.cs +++ b/src/MSBuild.UnitTests/XMake_Tests.cs @@ -2128,10 +2128,10 @@ public void RestoreFailsOnUnresolvedSdk() } /// - /// Verifies a non-existent target doesn't fail restore as long as its not considered "top-level" or a target that we're directly executing, in this case Restore. + /// Verifies a non-existent target doesn't fail restore as long as its not considered an entry target, in this case Restore. /// [Fact] - public void RestoreSkipsNonExistentNonTopLevelTargets() + public void RestoreSkipsNonExistentNonEntryTargets() { string restoreFirstProps = $"{Guid.NewGuid():N}.props"; @@ -2164,10 +2164,10 @@ public void RestoreSkipsNonExistentNonTopLevelTargets() } /// - /// Verifies restore will fail if the "top-level" target doesn't exist, in this case Restore. + /// Verifies restore will fail if the entry target doesn't exist, in this case Restore. /// [Fact] - public void RestoreFailsWhenTopLevelTargetIsNonExistent() + public void RestoreFailsWhenEntryTargetIsNonExistent() { string projectContents = ObjectModelHelpers.CleanupFileContents( @" @@ -2181,6 +2181,33 @@ public void RestoreFailsWhenTopLevelTargetIsNonExistent() logContents.ShouldContain("error MSB4057: The target \"Restore\" does not exist in the project."); } + /// + /// Verifies restore will run InitialTargets. + /// + [Fact] + public void RestoreRunsInitialTargets() + { + string projectContents = ObjectModelHelpers.CleanupFileContents( + @" + + + + + + + + + + + +"); + + string logContents = ExecuteMSBuildExeExpectSuccess(projectContents, arguments: "/t:restore"); + + logContents.ShouldContain("InitialTarget target ran"); + logContents.ShouldContain("Restore target ran"); + } + /// /// We check if there is only one target name specified and this logic caused a regression: https://github.com/Microsoft/msbuild/issues/3317 /// diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 7301ac1c84e..792410a9964 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -1422,7 +1422,7 @@ private static (BuildResultCode result, Exception exception) ExecuteRestore(stri // Create a new request with a Restore target only and specify: // - BuildRequestDataFlags.ClearCachesAfterBuild to ensure the projects will be reloaded from disk for subsequent builds - // - BuildRequestDataFlags.SkipNonexistentNonTopLevelTargets to ignore missing non-top-level targets since Restore does not require that all targets + // - BuildRequestDataFlags.SkipNonexistentNonEntryTargets to ignore missing non-entry targets since Restore does not require that all targets // exist, only top-level ones like Restore itself // - BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports to ignore imports that don't exist, are empty, or are invalid because restore might // make available an import that doesn't exist yet and the might be missing a condition. @@ -1434,7 +1434,7 @@ private static (BuildResultCode result, Exception exception) ExecuteRestore(stri toolsVersion, targetsToBuild: new[] { MSBuildConstants.RestoreTargetName }, hostServices: null, - flags: BuildRequestDataFlags.ClearCachesAfterBuild | BuildRequestDataFlags.SkipNonexistentNonTopLevelTargets | BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports | BuildRequestDataFlags.FailOnUnresolvedSdk); + flags: BuildRequestDataFlags.ClearCachesAfterBuild | BuildRequestDataFlags.SkipNonexistentNonEntryTargets | BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports | BuildRequestDataFlags.FailOnUnresolvedSdk); return ExecuteBuild(buildManager, restoreRequest); }