Skip to content

Commit a52c76e

Browse files
authored
Fix graph target list for multitargetting projects (#8565)
This change fixes graph builds for multitargetting projects using BuildProjectReferences=false Previously, when using BuildProjectReferences=false the graph would consider the outer build calling GetTargetPath on the inner builds. However, it actually calls Build when dispatching to the inner builds, and those call GetTargetPath on their dependencies. In effect this is causing graph builds to be non-graph builds since the target list is not accurately described. This change ensures the correct behavior by separating the ProjectReferenceTargets logic for single and multi-targetting projects.
1 parent 0aa8c5f commit a52c76e

File tree

2 files changed

+80
-12
lines changed

2 files changed

+80
-12
lines changed

src/Build.UnitTests/Graph/ProjectGraph_Tests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,6 +2508,71 @@ public void MultipleProjectReferencesSameFileDifferentTargets()
25082508
targetLists[project2].ShouldBe(new[] { "SomeDefaultTarget2", "SomeOtherTarget" });
25092509
}
25102510

2511+
[Fact]
2512+
public void MultitargettingTargetsWithBuildProjectReferencesFalse()
2513+
{
2514+
// This test should emulate Microsoft.Managed.After.targets's handling of multitargetting projects.
2515+
ProjectGraph graph = Helpers.CreateProjectGraph(
2516+
env: _env,
2517+
dependencyEdges: new Dictionary<int, int[]>()
2518+
{
2519+
{ 1, new[] { 2 } },
2520+
},
2521+
globalProperties: new Dictionary<string, string> { { "BuildProjectReferences", "false" } },
2522+
extraContentForAllNodes: """
2523+
<PropertyGroup>
2524+
<TargetFrameworks>netcoreapp3.1;net6.0;net7.0</TargetFrameworks>
2525+
</PropertyGroup>
2526+
2527+
<PropertyGroup Condition="'$(TargetFrameworks)' != '' and '$(TargetFramework)' == ''">
2528+
<IsCrossTargetingBuild>true</IsCrossTargetingBuild>
2529+
</PropertyGroup>
2530+
2531+
<PropertyGroup>
2532+
<InnerBuildProperty>TargetFramework</InnerBuildProperty>
2533+
<InnerBuildPropertyValues>TargetFrameworks</InnerBuildPropertyValues>
2534+
</PropertyGroup>
2535+
2536+
<PropertyGroup Condition="'$(IsGraphBuild)' == 'true' and '$(IsCrossTargetingBuild)' != 'true'">
2537+
<_MainReferenceTargetForBuild Condition="'$(BuildProjectReferences)' == '' or '$(BuildProjectReferences)' == 'true'">.projectReferenceTargetsOrDefaultTargets</_MainReferenceTargetForBuild>
2538+
<_MainReferenceTargetForBuild Condition="'$(_MainReferenceTargetForBuild)' == ''">GetTargetPath</_MainReferenceTargetForBuild>
2539+
2540+
<ProjectReferenceTargetsForBuild>$(_MainReferenceTargetForBuild);GetNativeManifest;$(_RecursiveTargetForContentCopying);$(ProjectReferenceTargetsForBuild)</ProjectReferenceTargetsForBuild>
2541+
</PropertyGroup>
2542+
<PropertyGroup Condition="'$(IsGraphBuild)' == 'true' and '$(IsCrossTargetingBuild)' == 'true'">
2543+
<ProjectReferenceTargetsForBuild>.default;$(ProjectReferenceTargetsForBuild)</ProjectReferenceTargetsForBuild>
2544+
</PropertyGroup>
2545+
2546+
<ItemGroup Condition="'$(IsGraphBuild)' == 'true'">
2547+
<ProjectReferenceTargets Include="Build" Targets="GetTargetFrameworks" OuterBuild="true" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
2548+
<ProjectReferenceTargets Include="Build" Targets="$(ProjectReferenceTargetsForBuild)" Condition=" '$(ProjectReferenceTargetsForBuild)' != '' " />
2549+
2550+
<ProjectReferenceTargets Include="Build" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
2551+
</ItemGroup>
2552+
2553+
<Target Name="Build" />
2554+
<Target Name="GetTargetPath" />
2555+
<Target Name="GetNativeManifest" />
2556+
<Target Name="GetTargetFrameworks" />
2557+
<Target Name="GetTargetFrameworksWithPlatformForSingleTargetFramework" />
2558+
""");
2559+
2560+
IReadOnlyDictionary<ProjectGraphNode, ImmutableList<string>> targetLists = graph.GetTargetLists(Array.Empty<string>());
2561+
2562+
targetLists[GetOuterBuild(graph, 1)].ShouldBe(new[] { "Build" });
2563+
foreach (ProjectGraphNode inner in GetInnerBuilds(graph, 1))
2564+
{
2565+
targetLists[inner].ShouldBe(new[] { "Build" });
2566+
}
2567+
2568+
targetLists[GetOuterBuild(graph, 2)].ShouldBe(new[] { "GetTargetFrameworks" });
2569+
foreach (ProjectGraphNode inner in GetInnerBuilds(graph, 2))
2570+
{
2571+
// GetTargetFrameworks actually shouldn't be here...
2572+
targetLists[inner].ShouldBe(new[] { "GetTargetFrameworks", "GetTargetPath", "GetNativeManifest", "GetTargetFrameworksWithPlatformForSingleTargetFramework" });
2573+
}
2574+
}
2575+
25112576
public void Dispose()
25122577
{
25132578
_env.Dispose();

src/Tasks/Microsoft.Managed.After.targets

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,13 @@ Copyright (C) Microsoft Corporation. All rights reserved.
3636
Properties for extension of ProjectReferenceTargets.
3737
Append any current value which may have been provided in a Directory.Build.props since the intent was likely to append, not prepend.
3838
-->
39-
<PropertyGroup Condition="'$(IsGraphBuild)' == 'true'">
40-
<!-- Empty case is for outer builds which do not import the target files that set BuildProjectReferences -->
39+
<PropertyGroup Condition="'$(IsGraphBuild)' == 'true' and '$(IsCrossTargetingBuild)' != 'true'">
40+
<!-- Empty case is for builds which do not import the target files that set BuildProjectReferences -->
4141
<_MainReferenceTargetForBuild Condition="'$(BuildProjectReferences)' == '' or '$(BuildProjectReferences)' == 'true'">.projectReferenceTargetsOrDefaultTargets</_MainReferenceTargetForBuild>
4242
<_MainReferenceTargetForBuild Condition="'$(_MainReferenceTargetForBuild)' == ''">GetTargetPath</_MainReferenceTargetForBuild>
4343

4444
<ProjectReferenceTargetsForBuild>$(_MainReferenceTargetForBuild);GetNativeManifest;$(_RecursiveTargetForContentCopying);$(ProjectReferenceTargetsForBuild)</ProjectReferenceTargetsForBuild>
4545

46-
<ProjectReferenceTargetsForClean>Clean;$(ProjectReferenceTargetsForClean)</ProjectReferenceTargetsForClean>
47-
48-
<ProjectReferenceTargetsForRebuild>$(ProjectReferenceTargetsForClean);$(ProjectReferenceTargetsForBuild);$(ProjectReferenceTargetsForRebuild)</ProjectReferenceTargetsForRebuild>
49-
5046
<!-- Publish has the same logic as Build for the main reference target except it also takes $(NoBuild) into account. -->
5147
<_MainReferenceTargetForPublish Condition="'$(NoBuild)' == 'true'">GetTargetPath</_MainReferenceTargetForPublish>
5248
<_MainReferenceTargetForPublish Condition="'$(NoBuild)' != 'true'">$(_MainReferenceTargetForBuild)</_MainReferenceTargetForPublish>
@@ -58,23 +54,30 @@ Copyright (C) Microsoft Corporation. All rights reserved.
5854

5955
<ProjectReferenceTargetsForGetCopyToPublishDirectoryItems>GetCopyToPublishDirectoryItems;$(ProjectReferenceTargetsForGetCopyToPublishDirectoryItems)</ProjectReferenceTargetsForGetCopyToPublishDirectoryItems>
6056
</PropertyGroup>
57+
<PropertyGroup Condition="'$(IsGraphBuild)' == 'true' and '$(IsCrossTargetingBuild)' == 'true'">
58+
<ProjectReferenceTargetsForBuild>.default;$(ProjectReferenceTargetsForBuild)</ProjectReferenceTargetsForBuild>
59+
</PropertyGroup>
60+
<PropertyGroup Condition="'$(IsGraphBuild)' == 'true'">
61+
<ProjectReferenceTargetsForClean>Clean;$(ProjectReferenceTargetsForClean)</ProjectReferenceTargetsForClean>
62+
<ProjectReferenceTargetsForRebuild>$(ProjectReferenceTargetsForClean);$(ProjectReferenceTargetsForBuild);$(ProjectReferenceTargetsForRebuild)</ProjectReferenceTargetsForRebuild>
63+
</PropertyGroup>
6164

6265
<ItemGroup Condition="'$(IsGraphBuild)' == 'true'">
6366
<ProjectReferenceTargets Include="Build" Targets="$(ProjectReferenceTargetsForBuildInOuterBuild)" Condition=" '$(ProjectReferenceTargetsForBuildInOuterBuild)' != '' " OuterBuild="true" />
64-
<ProjectReferenceTargets Include="Build" Targets="GetTargetFrameworks" OuterBuild="true" SkipNonexistentTargets="true" />
67+
<ProjectReferenceTargets Include="Build" Targets="GetTargetFrameworks" OuterBuild="true" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
6568
<ProjectReferenceTargets Include="Build" Targets="$(ProjectReferenceTargetsForBuild)" Condition=" '$(ProjectReferenceTargetsForBuild)' != '' " />
6669

6770
<ProjectReferenceTargets Include="Clean" Targets="$(ProjectReferenceTargetsForCleanInOuterBuild)" Condition=" '$(ProjectReferenceTargetsForCleanInOuterBuild)' != '' " OuterBuild="true" />
68-
<ProjectReferenceTargets Include="Clean" Targets="GetTargetFrameworks" OuterBuild="true" SkipNonexistentTargets="true" />
71+
<ProjectReferenceTargets Include="Clean" Targets="GetTargetFrameworks" OuterBuild="true" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
6972
<ProjectReferenceTargets Include="Clean" Targets="$(ProjectReferenceTargetsForClean)" Condition=" '$(ProjectReferenceTargetsForClean)' != '' " />
7073

7174
<!--
7275
Note: SkipNonexistentTargets="true" on the following three items means that an outer build node's call to its existent GetTargetFrameworks target will fail if its inner build nodes don't define GetTargetFrameworksWithPlatformForSingleTargetFrameworks.
7376
This is necessary since the P2P protocol cannot express the targets called from the outer build to the inner build.
7477
-->
75-
<ProjectReferenceTargets Include="Build" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" />
76-
<ProjectReferenceTargets Include="Clean" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" />
77-
<ProjectReferenceTargets Include="Rebuild" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" />
78+
<ProjectReferenceTargets Include="Build" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
79+
<ProjectReferenceTargets Include="Clean" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
80+
<ProjectReferenceTargets Include="Rebuild" Targets="GetTargetFrameworksWithPlatformForSingleTargetFramework" SkipNonexistentTargets="true" Condition="'$(IsCrossTargetingBuild)' != 'true'" />
7881

7982
<ProjectReferenceTargets Include="Rebuild" Targets="$(ProjectReferenceTargetsForRebuild)" Condition=" '$(ProjectReferenceTargetsForRebuild)' != '' " />
8083

@@ -83,4 +86,4 @@ Copyright (C) Microsoft Corporation. All rights reserved.
8386
<ProjectReferenceTargets Include="GetCopyToPublishDirectoryItems" Targets="$(ProjectReferenceTargetsForGetCopyToPublishDirectoryItems)" Condition=" '$(ProjectReferenceTargetsForGetCopyToPublishDirectoryItems)' != '' " />
8487
</ItemGroup>
8588

86-
</Project>
89+
</Project>

0 commit comments

Comments
 (0)