Skip to content

Commit

Permalink
Adding ability to override setplatform negotiation (#8594)
Browse files Browse the repository at this point in the history
With setplatform negotiation there is no way to force a project to as a certain platform. there is but that will override the feature all together and there is no way to set the platform to be blank. Because of this there is effectively no way to force a dependent project to build as its default value since platform=default will cause overbuilding and does nothing. here is an example

A( building as x64) references project B (Available platforms x86;x64 with default platform x86)

Platform negotiation will negotate to x64 since its available but if we actually wanted to reference b x86 its not possible
because we should leave platform blank if we want to build b as x86 but
and platform= are not valid ways to do this
therefore the only way to build b as x86 is platform=86 but this will lead to overbuilding if b is built once with global props {platform = x86} and once with global props {}
  • Loading branch information
MIchaelRShea committed Mar 29, 2023
1 parent d08de3a commit 8ead272
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 4 deletions.
42 changes: 42 additions & 0 deletions src/Build.UnitTests/Graph/GetCompatiblePlatformGraph_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,48 @@ public void ValidateSetPlatformOverride()
}
}

[Fact]
public void ValidateNegotiationOverride()
{
using (var env = TestEnvironment.Create())
{

TransientTestFile entryProject = CreateProjectFile(env, 1, extraContent: @"<PropertyGroup>
<EnableDynamicPlatformResolution>true</EnableDynamicPlatformResolution>
<Platform>x64</Platform>
<PlatformLookupTable>win32=x64</PlatformLookupTable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include=""$(MSBuildThisFileDirectory)2.proj"" >
<OverridePlatformNegotiationValue>x86</OverridePlatformNegotiationValue>
</ProjectReference>
</ItemGroup>");
var proj2 = env.CreateFile("2.proj", @"
<Project>
<PropertyGroup>
<EnableDynamicPlatformResolution>true</EnableDynamicPlatformResolution>
<Platforms>x64;AnyCPU</Platforms>
<Platform>x86</Platform>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include=""$(MSBuildThisFileDirectory)3.proj"" >
</ProjectReference>
</ItemGroup>
</Project>");
var proj3 = env.CreateFile("3.proj", @"
<Project>
<PropertyGroup>
<Platforms>AnyCPU;x86</Platforms>
</PropertyGroup>
</Project>");


ProjectGraph graph = new ProjectGraph(entryProject.Path);
GetFirstNodeWithProjectNumber(graph, 2).ProjectInstance.GlobalProperties.ContainsKey("Platform").ShouldBeFalse();
GetFirstNodeWithProjectNumber(graph, 3).ProjectInstance.GlobalProperties["Platform"].ShouldBe("x86");
}
}

[Fact]
public void ResolvesMultipleReferencesToSameProject()
{
Expand Down
5 changes: 4 additions & 1 deletion src/Build/Graph/ProjectInterpretation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ internal sealed class ProjectInterpretation
private const string PlatformMetadataName = "Platform";
private const string PlatformsMetadataName = "Platforms";
private const string EnableDynamicPlatformResolutionMetadataName = "EnableDynamicPlatformResolution";
private const string OverridePlatformNegotiationValue = "OverridePlatformNegotiationValue";

private static readonly char[] PropertySeparator = MSBuildConstants.SemicolonChar;

Expand Down Expand Up @@ -134,7 +135,9 @@ public IEnumerable<ReferenceInfo> GetReferences(ProjectInstance requesterInstanc
null, // Platform negotiation requires an evaluation with no global properties first
_projectCollection);

var selectedPlatform = PlatformNegotiation.GetNearestPlatform(projectInstance.GetPropertyValue(PlatformMetadataName), projectInstance.GetPropertyValue(PlatformsMetadataName), projectInstance.GetPropertyValue(PlatformLookupTableMetadataName), requesterInstance.GetPropertyValue(PlatformLookupTableMetadataName), projectInstance.FullPath, requesterInstance.GetPropertyValue(PlatformMetadataName));
string overridePlatformNegotiationMetadataValue = projectReferenceItem.GetMetadataValue(OverridePlatformNegotiationValue);

var selectedPlatform = PlatformNegotiation.GetNearestPlatform(overridePlatformNegotiationMetadataValue, projectInstance.GetPropertyValue(PlatformMetadataName), projectInstance.GetPropertyValue(PlatformsMetadataName), projectInstance.GetPropertyValue(PlatformLookupTableMetadataName), requesterInstance.GetPropertyValue(PlatformLookupTableMetadataName), projectInstance.FullPath, requesterInstance.GetPropertyValue(PlatformMetadataName));

if (selectedPlatform.Equals(String.Empty))
{
Expand Down
9 changes: 7 additions & 2 deletions src/Shared/PlatformNegotiation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Microsoft.Build.Shared
/// </summary>
internal static class PlatformNegotiation
{
internal static string GetNearestPlatform(string referencedProjectPlatform, string projectReferencePlatformsMetadata, string projectReferenceLookupTableMetadata, string platformLookupTable, string projectPath, string currentProjectPlatform, TaskLoggingHelper? log = null)
internal static string GetNearestPlatform(string overridePlatformValue, string referencedProjectPlatform, string projectReferencePlatformsMetadata, string projectReferenceLookupTableMetadata, string platformLookupTable, string projectPath, string currentProjectPlatform, TaskLoggingHelper? log = null)
{
Dictionary<string, string>? currentProjectLookupTable = ExtractLookupTable(platformLookupTable, log);

Expand All @@ -41,9 +41,14 @@ internal static string GetNearestPlatform(string referencedProjectPlatform, stri

string buildProjectReferenceAs = string.Empty;

// If an override value is set define that as the platform value as the top priority
if (!string.IsNullOrEmpty(overridePlatformValue))
{
buildProjectReferenceAs = overridePlatformValue;
}
// If the referenced project has a defined `Platform` that's compatible, it will build that way by default.
// Don't set `buildProjectReferenceAs` and the `_GetProjectReferencePlatformProperties` target will handle the rest.
if (!string.IsNullOrEmpty(referencedProjectPlatform) && referencedProjectPlatform.Equals(currentProjectPlatform, StringComparison.OrdinalIgnoreCase))
else if (!string.IsNullOrEmpty(referencedProjectPlatform) && referencedProjectPlatform.Equals(currentProjectPlatform, StringComparison.OrdinalIgnoreCase))
{
log?.LogMessageFromResources(MessageImportance.Low, "GetCompatiblePlatform.ReferencedProjectHasDefinitivePlatform", projectPath, referencedProjectPlatform);
}
Expand Down
23 changes: 23 additions & 0 deletions src/Tasks.UnitTests/GetCompatiblePlatform_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,29 @@ public void ResolvesViaPlatformLookupTable()
task.AssignedProjectsWithPlatform[0].GetMetadata("NearestPlatform").ShouldBe("x64");
}


[Fact]
public void ResolvesViaOverride()
{
// OverridePlatformNegotiationValue always takes priority over everything. It is typically user-defined.
TaskItem projectReference = new TaskItem("foo.bar");
projectReference.SetMetadata("Platforms", "x64;x86;AnyCPU");
projectReference.SetMetadata("platform", "x86");
projectReference.SetMetadata("OverridePlatformNegotiationValue", "x86");

GetCompatiblePlatform task = new GetCompatiblePlatform()
{
BuildEngine = new MockEngine(_output),
CurrentProjectPlatform = "x64",
PlatformLookupTable = "win32=x64",
AnnotatedProjects = new TaskItem[] { projectReference }
};

task.Execute().ShouldBeTrue();

task.AssignedProjectsWithPlatform[0].GetMetadata("NearestPlatform").ShouldBe("");
}

[Fact]
public void ResolvesViaProjectReferencesPlatformLookupTable()
{
Expand Down
3 changes: 2 additions & 1 deletion src/Tasks/GetCompatiblePlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ public override bool Execute()
string referencedProjectPlatform = AssignedProjectsWithPlatform[i].GetMetadata("Platform");
string projectReferencePlatformsMetadata = AssignedProjectsWithPlatform[i].GetMetadata("Platforms");
string projectReferenceLookupTableMetadata = AssignedProjectsWithPlatform[i].GetMetadata("PlatformLookupTable");
string projectReferenceOverridePlatformNegotiationMetadata = AssignedProjectsWithPlatform[i].GetMetadata("OverridePlatformNegotiationValue");

string? buildProjectReferenceAs = PlatformNegotiation.GetNearestPlatform(referencedProjectPlatform, projectReferencePlatformsMetadata, projectReferenceLookupTableMetadata, PlatformLookupTable, AssignedProjectsWithPlatform[i].ItemSpec, CurrentProjectPlatform, Log);
string? buildProjectReferenceAs = PlatformNegotiation.GetNearestPlatform(projectReferenceOverridePlatformNegotiationMetadata, referencedProjectPlatform, projectReferencePlatformsMetadata, projectReferenceLookupTableMetadata, PlatformLookupTable, AssignedProjectsWithPlatform[i].ItemSpec, CurrentProjectPlatform, Log);

AssignedProjectsWithPlatform[i].SetMetadata("NearestPlatform", buildProjectReferenceAs);
Log.LogMessageFromResources(MessageImportance.Low, "GetCompatiblePlatform.DisplayChosenPlatform", AssignedProjectsWithPlatform[i].ItemSpec, buildProjectReferenceAs);
Expand Down

0 comments on commit 8ead272

Please sign in to comment.