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);
}