Skip to content

Commit

Permalink
Expand usingtask customization (#7550)
Browse files Browse the repository at this point in the history
  • Loading branch information
benvillalobos authored Apr 19, 2022
1 parent 44ad46f commit 67deba3
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 44 deletions.
3 changes: 3 additions & 0 deletions src/Build.UnitTests/BuildEnvironmentHelper_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ public void BuildEnvironmentFindsAmd64()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/msbuild/issues/7552", TargetFrameworkMonikers.Any)]
[PlatformSpecific(TestPlatforms.Windows)]
public void BuildEnvironmentFindsAmd64RunningInAmd64NoVS()
{
Expand All @@ -386,6 +387,7 @@ public void BuildEnvironmentFindsAmd64RunningInAmd64NoVS()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/msbuild/issues/7552", TargetFrameworkMonikers.Any)]
[PlatformSpecific(TestPlatforms.Windows)]
public void BuildEnvironmentFindsAmd64NoVS()
{
Expand All @@ -401,6 +403,7 @@ public void BuildEnvironmentFindsAmd64NoVS()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/msbuild/issues/7552", TargetFrameworkMonikers.Any)]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp, "No Visual Studio install for netcore")]
[PlatformSpecific(TestPlatforms.Windows)]
public void BuildEnvironmentFindsAmd64RunningInAmd64()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ internal NodeEndpointOutOfProc(
/// </summary>
protected override Handshake GetHandshake()
{
return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, is64Bit: EnvironmentUtilities.Is64BitProcess, nodeReuse: _enableReuse, lowPriority: _lowPriority));
return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, architectureFlagToSet: XMakeAttributes.GetCurrentMSBuildArchitecture(), nodeReuse: _enableReuse, lowPriority: _lowPriority));
}

#region Structs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public int AvailableNodes
internal static Handshake GetHandshake(bool enableNodeReuse, bool enableLowPriority)
{
CommunicationsUtilities.Trace("MSBUILDNODEHANDSHAKESALT=\"{0}\", msbuildDirectory=\"{1}\", enableNodeReuse={2}, enableLowPriority={3}", Traits.MSBuildNodeHandshakeSalt, BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32, enableNodeReuse, enableLowPriority);
return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, is64Bit: EnvironmentUtilities.Is64BitProcess));
return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, architectureFlagToSet: XMakeAttributes.GetCurrentMSBuildArchitecture(), nodeReuse: enableNodeReuse, lowPriority: enableLowPriority));
}

/// <summary>
Expand All @@ -94,7 +94,7 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration
// Make it here.
CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId);

Handshake hostHandshake = new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, nodeReuse: ComponentHost.BuildParameters.EnableNodeReuse, lowPriority: ComponentHost.BuildParameters.LowPriority, is64Bit: EnvironmentUtilities.Is64BitProcess));
Handshake hostHandshake = new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, architectureFlagToSet: XMakeAttributes.GetCurrentMSBuildArchitecture(), nodeReuse: ComponentHost.BuildParameters.EnableNodeReuse, lowPriority: ComponentHost.BuildParameters.LowPriority));
NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, hostHandshake, NodeContextTerminated);

if (context != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ internal class NodeProviderOutOfProcTaskHost : NodeProviderOutOfProcBase, INodeP
/// </summary>
private static string s_baseTaskHostPath64;

/// <summary>
/// Store the 64-bit path for MSBuild / MSBuildTaskHost so that we don't have to keep recalculating it.
/// </summary>
private static string s_baseTaskHostPathArm64;

/// <summary>
/// Store the path for the 32-bit MSBuildTaskHost so that we don't have to keep re-calculating it.
/// </summary>
Expand All @@ -57,6 +62,11 @@ internal class NodeProviderOutOfProcTaskHost : NodeProviderOutOfProcBase, INodeP
/// </summary>
private static string s_pathToX64Clr4;

/// <summary>
/// Store the path for the 64-bit MSBuild so that we don't have to keep re-calculating it.
/// </summary>
private static string s_pathToArm64Clr4;

/// <summary>
/// Name for MSBuild.exe
/// </summary>
Expand Down Expand Up @@ -353,8 +363,10 @@ internal static void ClearCachedTaskHostPaths()
s_pathToX32Clr4 = null;
s_pathToX64Clr2 = null;
s_pathToX64Clr4 = null;
s_pathToArm64Clr4 = null;
s_baseTaskHostPath = null;
s_baseTaskHostPath64 = null;
s_baseTaskHostPathArm64 = null;
}

/// <summary>
Expand Down Expand Up @@ -392,13 +404,20 @@ internal static string GetTaskHostNameFromHostContext(HandshakeOptions hostConte
internal static string GetMSBuildLocationFromHostContext(HandshakeOptions hostContext)
{
string toolName = GetTaskHostNameFromHostContext(hostContext);
string toolPath;
string toolPath = null;

s_baseTaskHostPath = BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32;
s_baseTaskHostPath64 = BuildEnvironmentHelper.Instance.MSBuildToolsDirectory64;
s_baseTaskHostPathArm64 = BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryArm64;

ErrorUtilities.VerifyThrowInternalErrorUnreachable((hostContext & HandshakeOptions.TaskHost) == HandshakeOptions.TaskHost);

if ((hostContext & HandshakeOptions.X64) == HandshakeOptions.X64 && (hostContext & HandshakeOptions.CLR2) == HandshakeOptions.CLR2)
if ((hostContext & HandshakeOptions.Arm64) == HandshakeOptions.Arm64 && (hostContext & HandshakeOptions.CLR2) == HandshakeOptions.CLR2)
{
// Unsupported, throw.
ErrorUtilities.ThrowInternalError("ARM64 CLR2 task hosts are not supported.");
}
else if ((hostContext & HandshakeOptions.X64) == HandshakeOptions.X64 && (hostContext & HandshakeOptions.CLR2) == HandshakeOptions.CLR2)
{
if (s_pathToX64Clr2 == null)
{
Expand Down Expand Up @@ -434,6 +453,15 @@ internal static string GetMSBuildLocationFromHostContext(HandshakeOptions hostCo

toolPath = s_pathToX64Clr4;
}
else if ((hostContext & HandshakeOptions.Arm64) == HandshakeOptions.Arm64)
{
if (s_pathToArm64Clr4 == null)
{
s_pathToArm64Clr4 = s_baseTaskHostPathArm64;
}

toolPath = s_pathToArm64Clr4;
}
else
{
if (s_pathToX32Clr4 == null)
Expand Down
62 changes: 35 additions & 27 deletions src/Shared/BuildEnvironmentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;

using Microsoft.Build.Framework;
using Microsoft.Build.Shared.FileSystem;
using System.Reflection;

Expand Down Expand Up @@ -531,42 +532,38 @@ public BuildEnvironment(BuildEnvironmentMode mode, string currentMSBuildExePath,
if (mode == BuildEnvironmentMode.None || currentMSBuildExeFile == null || currentToolsDirectory == null)
return;

// Check to see if our current folder is 'amd64'
bool runningInAmd64 = string.Equals(currentToolsDirectory.Name, "amd64", StringComparison.OrdinalIgnoreCase);
bool runningInARM64 = string.Equals(currentToolsDirectory.Name, "arm64", StringComparison.OrdinalIgnoreCase);

var msBuildExeName = currentMSBuildExeFile.Name;
var folderAbove = currentToolsDirectory.Parent?.FullName;

if (folderAbove != null)
if (mode == BuildEnvironmentMode.VisualStudio)
{
// In Visual Studio, the entry-point MSBuild.exe is often from an arch-specific subfolder
MSBuildToolsDirectoryRoot = NativeMethodsShared.ProcessorArchitecture switch
{
NativeMethodsShared.ProcessorArchitectures.X86 => CurrentMSBuildToolsDirectory,
NativeMethodsShared.ProcessorArchitectures.X64 or NativeMethodsShared.ProcessorArchitectures.ARM64
=> currentToolsDirectory.Parent?.FullName,
_ => throw new InternalErrorException("Unknown processor architecture " + NativeMethodsShared.ProcessorArchitecture),
};
}
else
{
// In the .NET SDK, there's one copy of MSBuild.dll and it's in the root folder.
MSBuildToolsDirectoryRoot = CurrentMSBuildToolsDirectory;
}

if (mode == BuildEnvironmentMode.VisualStudio && MSBuildToolsDirectoryRoot != null)
{
// Calculate potential paths to other architecture MSBuild.exe
var potentialAmd64FromX86 = FileUtilities.CombinePaths(CurrentMSBuildToolsDirectory, "amd64", msBuildExeName);
var potentialARM64FromX86 = FileUtilities.CombinePaths(CurrentMSBuildToolsDirectory, "arm64", msBuildExeName);
var potentialX86FromAmd64 = Path.Combine(folderAbove, msBuildExeName);
var potentialAmd64FromX86 = FileUtilities.CombinePaths(MSBuildToolsDirectoryRoot, "amd64", msBuildExeName);
var potentialARM64FromX86 = FileUtilities.CombinePaths(MSBuildToolsDirectoryRoot, "arm64", msBuildExeName);

// Check for existence of an MSBuild file. Note this is not necessary in a VS installation where we always want to
// assume the correct layout.
var existsCheck = mode == BuildEnvironmentMode.VisualStudio ? new Func<string, bool>(_ => true) : File.Exists;

if ((runningInARM64 || runningInAmd64) && existsCheck(potentialX86FromAmd64))
{
MSBuildToolsDirectory32 = folderAbove;
MSBuildToolsDirectory64 = CurrentMSBuildToolsDirectory;
}
else if (!runningInAmd64 && !runningInARM64)
{
MSBuildToolsDirectory32 = CurrentMSBuildToolsDirectory;

if (existsCheck(potentialARM64FromX86) && NativeMethodsShared.ProcessorArchitecture == Framework.NativeMethods.ProcessorArchitectures.ARM64)
{
MSBuildToolsDirectory64 = Path.Combine(CurrentMSBuildToolsDirectory, "arm64");
}
else if (existsCheck(potentialAmd64FromX86))
{
MSBuildToolsDirectory64 = Path.Combine(CurrentMSBuildToolsDirectory, "amd64");
}
}
MSBuildToolsDirectory32 = MSBuildToolsDirectoryRoot;
MSBuildToolsDirectory64 = Path.Combine(MSBuildToolsDirectoryRoot, "amd64");
MSBuildToolsDirectoryArm64 = File.Exists(potentialARM64FromX86) ? Path.Combine(MSBuildToolsDirectoryRoot, "arm64") : null;
}

MSBuildExtensionsPath = mode == BuildEnvironmentMode.VisualStudio
Expand All @@ -586,6 +583,11 @@ public BuildEnvironment(BuildEnvironmentMode mode, string currentMSBuildExePath,
/// </summary>
internal bool RunningInVisualStudio { get; }

/// <summary>
/// Path to the root of the MSBuild folder (in VS scenarios, <c>MSBuild\Current\bin</c>).
/// </summary>
internal string MSBuildToolsDirectoryRoot { get; }

/// <summary>
/// Path to the MSBuild 32-bit tools directory.
/// </summary>
Expand All @@ -596,6 +598,12 @@ public BuildEnvironment(BuildEnvironmentMode mode, string currentMSBuildExePath,
/// </summary>
internal string MSBuildToolsDirectory64 { get; }

/// <summary>
/// Path to the ARM64 tools directory.
/// <see langword="null" /> if ARM64 tools are not installed.
/// </summary>
internal string MSBuildToolsDirectoryArm64 { get; }

/// <summary>
/// Path to the Sdks folder for this MSBuild instance.
/// </summary>
Expand Down
34 changes: 23 additions & 11 deletions src/Shared/CommunicationsUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ internal enum HandshakeOptions
/// Using the .NET Core/.NET 5.0+ runtime
/// </summary>
NET = 64,

/// <summary>
/// ARM64 process
/// </summary>
Arm64 = 128,
}

internal readonly struct Handshake
Expand All @@ -90,9 +95,9 @@ internal Handshake(HandshakeOptions nodeType)
CommunicationsUtilities.Trace("Building handshake for node type {0}, (version {1}): options {2}.", nodeType, handshakeVersion, options);

string handshakeSalt = Environment.GetEnvironmentVariable("MSBUILDNODEHANDSHAKESALT");
CommunicationsUtilities.Trace("Handshake salt is \"{0}\"", handshakeSalt);
string toolsDirectory = (nodeType & HandshakeOptions.X64) == HandshakeOptions.X64 ? BuildEnvironmentHelper.Instance.MSBuildToolsDirectory64 : BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32;
CommunicationsUtilities.Trace("Tools directory is \"{0}\"", toolsDirectory);
CommunicationsUtilities.Trace("Handshake salt is " + handshakeSalt);
string toolsDirectory = BuildEnvironmentHelper.Instance.MSBuildToolsDirectoryRoot;
CommunicationsUtilities.Trace("Tools directory root is " + toolsDirectory);
salt = CommunicationsUtilities.GetHashCode(handshakeSalt + toolsDirectory);
Version fileVersion = new Version(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion);
fileVersionMajor = fileVersion.Major;
Expand Down Expand Up @@ -483,22 +488,22 @@ internal static async Task<int> ReadAsync(Stream stream, byte[] buffer, int byte
/// <summary>
/// Given the appropriate information, return the equivalent HandshakeOptions.
/// </summary>
internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit = false, bool nodeReuse = false, bool lowPriority = false, IDictionary<string, string> taskHostParameters = null)
internal static HandshakeOptions GetHandshakeOptions(bool taskHost, string architectureFlagToSet = null, bool nodeReuse = false, bool lowPriority = false, IDictionary<string, string> taskHostParameters = null)
{
HandshakeOptions context = taskHost ? HandshakeOptions.TaskHost : HandshakeOptions.None;

int clrVersion = 0;

// We don't know about the TaskHost. Figure it out.
// We don't know about the TaskHost.
if (taskHost)
{
// Take the current TaskHost context
// No parameters given, default to current
if (taskHostParameters == null)
{
clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major;
is64Bit = XMakeAttributes.GetCurrentMSBuildArchitecture().Equals(XMakeAttributes.MSBuildArchitectureValues.x64);
architectureFlagToSet = XMakeAttributes.GetCurrentMSBuildArchitecture();
}
else
else // Figure out flags based on parameters given
{
ErrorUtilities.VerifyThrow(taskHostParameters.TryGetValue(XMakeAttributes.runtime, out string runtimeVersion), "Should always have an explicit runtime when we call this method.");
ErrorUtilities.VerifyThrow(taskHostParameters.TryGetValue(XMakeAttributes.architecture, out string architecture), "Should always have an explicit architecture when we call this method.");
Expand All @@ -520,13 +525,20 @@ internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit
ErrorUtilities.ThrowInternalErrorUnreachable();
}

is64Bit = architecture.Equals(XMakeAttributes.MSBuildArchitectureValues.x64);
architectureFlagToSet = architecture;
}
}

if (is64Bit)
if (!string.IsNullOrEmpty(architectureFlagToSet))
{
context |= HandshakeOptions.X64;
if (architectureFlagToSet.Equals(XMakeAttributes.MSBuildArchitectureValues.x64, StringComparison.OrdinalIgnoreCase))
{
context |= HandshakeOptions.X64;
}
else if (architectureFlagToSet.Equals(XMakeAttributes.MSBuildArchitectureValues.arm64, StringComparison.OrdinalIgnoreCase))
{
context |= HandshakeOptions.Arm64;
}
}

switch (clrVersion)
Expand Down
24 changes: 23 additions & 1 deletion src/Shared/XMakeAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

using System;
using System.Collections.Generic;
#if !CLR2COMPATIBILITY
using System.Runtime.InteropServices;
#endif
using System.Runtime.CompilerServices;

#nullable disable
Expand Down Expand Up @@ -88,6 +91,7 @@ internal struct MSBuildArchitectureValues
{
internal const string x86 = "x86";
internal const string x64 = "x64";
internal const string arm64 = "arm64";
internal const string currentArchitecture = "CurrentArchitecture";
internal const string any = "*";
}
Expand All @@ -106,7 +110,7 @@ internal struct MSBuildArchitectureValues

private static readonly HashSet<string> ValidMSBuildRuntimeValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { MSBuildRuntimeValues.clr2, MSBuildRuntimeValues.clr4, MSBuildRuntimeValues.currentRuntime, MSBuildRuntimeValues.net, MSBuildRuntimeValues.any };

private static readonly HashSet<string> ValidMSBuildArchitectureValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { MSBuildArchitectureValues.x86, MSBuildArchitectureValues.x64, MSBuildArchitectureValues.currentArchitecture, MSBuildArchitectureValues.any };
private static readonly HashSet<string> ValidMSBuildArchitectureValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { MSBuildArchitectureValues.x86, MSBuildArchitectureValues.x64, MSBuildArchitectureValues.arm64, MSBuildArchitectureValues.currentArchitecture, MSBuildArchitectureValues.any };

/// <summary>
/// Returns true if and only if the specified attribute is one of the attributes that the engine specifically recognizes
Expand Down Expand Up @@ -429,7 +433,25 @@ internal static bool TryMergeArchitectureValues(string architectureA, string arc
/// </comments>
internal static string GetCurrentMSBuildArchitecture()
{
#if !CLR2COMPATIBILITY
string currentArchitecture = string.Empty;
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.X86:
currentArchitecture = MSBuildArchitectureValues.x86;
break;
case Architecture.X64:
currentArchitecture = MSBuildArchitectureValues.x64;
break;
case Architecture.Arm64:
currentArchitecture = MSBuildArchitectureValues.arm64;
break;
default:
throw new PlatformNotSupportedException(string.Format("{0} is not a supported architecture.", RuntimeInformation.ProcessArchitecture));
}
#else
string currentArchitecture = (IntPtr.Size == sizeof(Int64)) ? MSBuildArchitectureValues.x64 : MSBuildArchitectureValues.x86;
#endif
return currentArchitecture;
}

Expand Down

0 comments on commit 67deba3

Please sign in to comment.