Enable TaskHostFactory for .NET (Core) MSBuild (#6994)

Fixes #5158

Context
A task author can force any task to run out of process by specifying that it must run with TaskFactory="TaskHostFactory". But we never made this work on .NET Core; it fails with an error like

S:\msbuild\foo.proj(8,5): error MSB4216: Could not run the "Message" task because MSBuild could not create or connect to a task host with runtime "CLR4" and architecture "x64".  Please ensure that (1) the requested runtime and/or architecture are available on the machine, and (2) that the required executable "S:\msbuild\.dotnet\sdk\6.0.100-rc.1.21458.32\MSBuild.exe" exists and can be run.
That's because the "default" task host runtime was hardcoded to be CLR4 (even when on .NET 6.0+).

Changes Made
Created GetCurrentMSBuildRuntime() and used it; plumbed the new value around and checked for it in a few places. Eliminated FEATURE_TASKHOST since it's on everywhere now. Unified the named-pipe-name computation code (before it was using a different pipe name for taskhost pipes on UNIX).

Testing
Re-enabled tests for this behavior that have been disabled on .NET Core. Extended some to account for the NET runtime.

Specific steps:

* Enable out-of-proc TaskHosts on .NET Core

* Promote FEATURE_TASKHOST to no-flag-needed

This enables taskhost tests on .NET Core. Includes a couple of low-
complexity test fixes.

* Enable checking runtimetype in .tasks file

* Check runtime type in tasks file

* Extend TestRuntimeValuesMatch for net

* Extend RuntimeValuesMatch for net

* Split and shouldly-ify TestMergeRuntimeValues

* Use explicit current runtime/arch in CreatableByTaskFactoryMatchingIdentity

* Unify to NamedPipeUtil.GetPipeNameOrPath
This commit is contained in:
Rainer Sigwald 2021-11-15 13:25:17 -06:00 коммит произвёл GitHub
Родитель 37c6111333
Коммит 88882b971b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 205 добавлений и 88 удалений

Просмотреть файл

@ -0,0 +1,21 @@
# MSBuild's reserved and built-in properties
The MSBuild engine itself sets some properties for all projects. There is normal documentation for the [reserved properties and their meanings](https://docs.microsoft.com/visualstudio/msbuild/msbuild-reserved-and-well-known-properties). This document describes the implementation of these properties in MSBuild itself.
There are actually two different implementations of this functionality in MSBuild.
## Built-in properties
When evaluating an individual project, Pass 0 of the evaluation calls [`AddBuiltInProperties()`][addbuiltinproperties] which in turn calls [`SetBuiltInProperty()`][setbuiltinproperty] which sets the property basically as normal.
However, properties set there are not available at all parts of execution, and specifically they're not available when evaluating the `.tasks` file that makes MSBuild's built-in tasks available by default to all projects.
## Reserved properties
Reserved properties are [set by the toolset][toolset_reservedproperties] and are available _only_ in the `.tasks` and `.overridetasks` cases. Properties set there are not available in normal project evaluation.
[addbuiltinproperties]: https://github.com/dotnet/msbuild/blob/24b33188f385cee07804cc63ec805216b3f8b72f/src/Build/Evaluation/Evaluator.cs#L609-L612
[setbuiltinproperty]: https://github.com/dotnet/msbuild/blob/24b33188f385cee07804cc63ec805216b3f8b72f/src/Build/Evaluation/Evaluator.cs#L1257
[toolset_reservedproperties]: https://github.com/dotnet/msbuild/blob/24b33188f385cee07804cc63ec805216b3f8b72f/src/Build/Definition/Toolset.cs#L914-L921

Просмотреть файл

@ -184,8 +184,8 @@ namespace Microsoft.Build.UnitTests.BackEnd
SetupTaskFactory(factoryIdentityParameters, false /* don't want task host */);
IDictionary<string, string> taskIdentityParameters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
taskIdentityParameters.Add(XMakeAttributes.runtime, XMakeAttributes.MSBuildRuntimeValues.clr4);
taskIdentityParameters.Add(XMakeAttributes.architecture, XMakeAttributes.MSBuildArchitectureValues.any);
taskIdentityParameters.Add(XMakeAttributes.runtime, XMakeAttributes.GetCurrentMSBuildRuntime());
taskIdentityParameters.Add(XMakeAttributes.architecture, XMakeAttributes.GetCurrentMSBuildArchitecture());
Assert.True(_taskFactory.TaskNameCreatableByFactory("TaskToTestFactories", taskIdentityParameters, String.Empty, null, ElementLocation.Create(".", 1, 1)));
}
@ -309,7 +309,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
try
{
IDictionary<string, string> taskParameters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
taskParameters.Add(XMakeAttributes.runtime, XMakeAttributes.MSBuildRuntimeValues.clr4);
taskParameters.Add(XMakeAttributes.runtime, XMakeAttributes.GetCurrentMSBuildRuntime());
taskParameters.Add(XMakeAttributes.architecture, XMakeAttributes.GetCurrentMSBuildArchitecture());
createdTask = _taskFactory.CreateTaskInstance(ElementLocation.Create("MSBUILD"), null, new MockHost(), taskParameters,
@ -406,7 +406,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
try
{
IDictionary<string, string> factoryParameters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
factoryParameters.Add(XMakeAttributes.runtime, XMakeAttributes.MSBuildRuntimeValues.clr4);
factoryParameters.Add(XMakeAttributes.runtime, XMakeAttributes.GetCurrentMSBuildRuntime());
SetupTaskFactory(factoryParameters, false /* don't want task host */);

Просмотреть файл

@ -1598,7 +1598,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
_logger.AssertLogDoesntContain("[errormessage]");
}
#if FEATURE_TASKHOST && !NO_MSBUILDTASKHOST
#if !NO_MSBUILDTASKHOST
// Run this test only if we expect MSBuildTaskHost to have been produced, which requires that MSBuildTaskHost.csproj
// be built with full-framework MSBuild (so that it can target .NET 3.5).
@ -1672,7 +1672,6 @@ namespace Microsoft.Build.UnitTests.BackEnd
_logger.AssertLogDoesntContain("[errormessage]");
}
#if FEATURE_TASKHOST
/// <summary>
/// A canceled build which waits for the task to get started before canceling. Because it is a 12.0 task, we should
/// cancel the task and exit out after a short period wherein we wait for the task to exit cleanly.
@ -1706,7 +1705,6 @@ namespace Microsoft.Build.UnitTests.BackEnd
// Task host should not have exited prematurely
_logger.AssertLogDoesntContain("MSB4217");
}
#endif
/// <summary>
/// This test verifies that builds of the same project instance in sequence are permitted.
@ -4360,10 +4358,8 @@ $@"<Project InitialTargets=`Sleep`>
[Theory]
[InlineData("", false)] // regular task host, input logging disabled
[InlineData("", true)] // regular task host, input logging enabled
#if NETFRAMEWORK // https://github.com/microsoft/msbuild/issues/5158
[InlineData("TaskHostFactory", false)] // OOP task host, input logging disabled
[InlineData("TaskHostFactory", true)] // OOP task host, input logging enabled
#endif
public void TaskInputLoggingIsExposedToTasks(string taskFactory, bool taskInputLoggingEnabled)
{
string projectContents = ObjectModelHelpers.CleanupFileContents(@"<Project>

Просмотреть файл

@ -12,7 +12,6 @@ namespace Microsoft.Build.Engine.UnitTests.BackEnd
public sealed class TaskHostFactory_Tests
{
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp, "https://github.com/microsoft/msbuild/issues/5158")]
[Trait("Category", "mono-osx-failing")]
public void TaskNodesDieAfterBuild()
{

Просмотреть файл

@ -94,7 +94,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
logger.AssertLogContains("Property value is 'abc ; def ; ghi'");
}
#if FEATURE_TASKHOST
/// <summary>
/// Make sure I can define a property with escaped characters and pass it into
/// a string parameter of a task, in this case the Message task.
@ -117,7 +116,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
logger.AssertLogContains("Property value is 'abc ; def ; ghi'");
}
#endif
#if FEATURE_ASSEMBLY_LOCATION
/// <summary>
@ -588,7 +586,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
logger.AssertLogContains("Transformed item list: 'X;X%3bX.txt Y;Y%3bY.txt Z;Z%3bZ.txt'");
}
#if FEATURE_TASKHOST
/// <summary>
/// Do an item transform, where the transform expression contains an unescaped semicolon as well
/// as an escaped percent sign.
@ -616,7 +613,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
logger.AssertLogContains("Transformed item list: 'X;X%3bX.txt Y;Y%3bY.txt Z;Z%3bZ.txt'");
}
#endif
/// <summary>
/// Tests that when we add an item and are in a directory with characters in need of escaping, and the
@ -710,7 +706,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
}
}
#if FEATURE_TASKHOST
/// <summary>
/// If %2A (escaped '*') or %3F (escaped '?') is in an item's Include, it should be treated
/// literally, not as a wildcard
@ -747,7 +742,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
ObjectModelHelpers.DeleteTempProjectDirectory();
}
}
#endif
/// <summary>
/// Parity with Orcas: Target names are always unescaped, and in fact, if there are two targets,
@ -1002,7 +996,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
logger.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\a;b'c\ClassLibrary16.dll")));
}
#if FEATURE_TASKHOST
/// <summary>
/// ESCAPING: Escaping in conditionals is broken.
/// </summary>
@ -1071,7 +1064,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
Environment.SetEnvironmentVariable("MSBUILDFORCEALLTASKSOUTOFPROC", originalOverrideTaskHostVariable);
}
}
#endif
/// <summary>
/// ESCAPING: CopyBuildTarget target fails if the output assembly name contains a semicolon or single-quote
@ -1127,7 +1119,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
log.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\Debug\Class;Library16.dll")));
}
#if FEATURE_TASKHOST
/// <summary>
/// ESCAPING: CopyBuildTarget target fails if the output assembly name contains a semicolon or single-quote
/// </summary>
@ -1191,7 +1182,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
Environment.SetEnvironmentVariable("MSBUILDFORCEALLTASKSOUTOFPROC", originalOverrideTaskHostVariable);
}
}
#endif
/// <summary>
/// ESCAPING: Conversion Issue: Properties with $(xxx) as literals are not being converted correctly
@ -1247,7 +1237,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
log.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\Debug\Class$(prop)Library16.dll")));
}
#if FEATURE_TASKHOST
/// <summary>
/// ESCAPING: Conversion Issue: Properties with $(xxx) as literals are not being converted correctly
/// </summary>
@ -1311,7 +1300,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
Environment.SetEnvironmentVariable("MSBUILDFORCEALLTASKSOUTOFPROC", originalOverrideTaskHostVariable);
}
}
#endif
/// <summary>
/// This is the case when one of the source code files in the project has a filename containing a semicolon.
@ -1367,7 +1355,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
log.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\Debug\ClassLibrary16.dll")));
}
#if FEATURE_TASKHOST
/// <summary>
/// This is the case when one of the source code files in the project has a filename containing a semicolon.
/// </summary>
@ -1431,7 +1418,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
Environment.SetEnvironmentVariable("MSBUILDFORCEALLTASKSOUTOFPROC", originalOverrideTaskHostVariable);
}
}
#endif
/// <summary>
/// Build a .SLN file using MSBuild. The .SLN and the projects contained within
@ -1599,7 +1585,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
Assert.True(File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"SLN;!@(foo)'^1\Console;!@(foo)'^(Application1\bin\debug\Console;!@(foo)'^(Application1.exe"))); // @"Did not find expected file Console;!@(foo)'^(Application1.exe"
}
#if FEATURE_TASKHOST
/// <summary>
/// Build a .SLN file using MSBuild. The .SLN and the projects contained within
/// have all sorts of crazy characters in their name. There
@ -1775,7 +1760,6 @@ namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
Environment.SetEnvironmentVariable("MSBUILDFORCEALLTASKSOUTOFPROC", originalOverrideTaskHostVariable);
}
}
#endif
}
#endif

Просмотреть файл

@ -29,12 +29,10 @@ namespace Microsoft.Build.BackEnd
/// <summary>
/// Instantiates an endpoint to act as a client
/// </summary>
/// <param name="pipeName">The name of the pipe to which we should connect.</param>
/// <param name="host">The component host.</param>
/// <param name="enableReuse">Whether this node may be reused for a later build.</param>
/// <param name="lowPriority">Whether this node is low priority.</param>
internal NodeEndpointOutOfProc(
string pipeName,
IBuildComponentHost host,
bool enableReuse,
bool lowPriority)
@ -44,7 +42,7 @@ namespace Microsoft.Build.BackEnd
_enableReuse = enableReuse;
_lowPriority = lowPriority;
InternalConstruct(pipeName);
InternalConstruct();
}
#endregion

Просмотреть файл

@ -355,7 +355,7 @@ namespace Microsoft.Build.BackEnd
private Stream TryConnectToProcess(int nodeProcessId, int timeout, Handshake handshake)
{
// Try and connect to the process.
string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + nodeProcessId);
string pipeName = NamedPipeUtil.GetPipeNameOrPath(nodeProcessId);
NamedPipeClientStream nodeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous
#if FEATURE_PIPEOPTIONS_CURRENTUSERONLY

Просмотреть файл

@ -372,7 +372,9 @@ namespace Microsoft.Build.BackEnd
if (s_msbuildName == null)
{
s_msbuildName = "MSBuild.exe";
s_msbuildName = (hostContext & HandshakeOptions.NET) == HandshakeOptions.NET
? "MSBuild.dll"
: "MSBuild.exe";
}
}

Просмотреть файл

@ -239,9 +239,8 @@ namespace Microsoft.Build.Execution
public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out Exception shutdownException)
{
// Console.WriteLine("Run called at {0}", DateTime.Now);
string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id);
_nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority);
_nodeEndpoint = new NodeEndpointOutOfProc(this, enableReuse, lowPriority);
_nodeEndpoint.OnLinkStatusChanged += OnLinkStatusChanged;
_nodeEndpoint.Listen(this);

Просмотреть файл

@ -920,6 +920,17 @@ namespace Microsoft.Build.Evaluation
reservedProperties.Add(ProjectPropertyInstance.Create(ReservedPropertyNames.assemblyVersion, Constants.AssemblyVersion, mayBeReserved: true));
reservedProperties.Add(ProjectPropertyInstance.Create(ReservedPropertyNames.version, MSBuildAssemblyFileVersion.Instance.MajorMinorBuild, mayBeReserved: true));
reservedProperties.Add(ProjectPropertyInstance.Create(ReservedPropertyNames.msbuildRuntimeType,
#if RUNTIME_TYPE_NETCORE
"Core",
#elif MONO
NativeMethodsShared.IsMono ? "Mono" : "Full");
#else
"Full",
#endif
mayBeReserved: true));
// Add one for the subtoolset version property -- it may or may not be set depending on whether it has already been set by the
// environment or global properties, but it's better to create a dictionary that's one too big than one that's one too small.
int count = _environmentProperties.Count + reservedProperties.Count + Properties.Values.Count + _globalProperties.Count + 1;

Просмотреть файл

@ -355,15 +355,12 @@ namespace Microsoft.Build.BackEnd
mergedParameters ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
string runtime = null;
string architecture = null;
if (!mergedParameters.TryGetValue(XMakeAttributes.runtime, out runtime))
if (!mergedParameters.ContainsKey(XMakeAttributes.runtime))
{
mergedParameters[XMakeAttributes.runtime] = XMakeAttributes.MSBuildRuntimeValues.clr4;
mergedParameters[XMakeAttributes.runtime] = XMakeAttributes.GetCurrentMSBuildRuntime();
}
if (!mergedParameters.TryGetValue(XMakeAttributes.architecture, out architecture))
if (!mergedParameters.ContainsKey(XMakeAttributes.architecture))
{
mergedParameters[XMakeAttributes.architecture] = XMakeAttributes.GetCurrentMSBuildArchitecture();
}

Просмотреть файл

@ -80,7 +80,6 @@
<DefineConstants>$(DefineConstants);FEATURE_SYSTEMPAGESIZE</DefineConstants>
<FeatureSystemConfiguration>true</FeatureSystemConfiguration>
<DefineConstants>$(DefineConstants);FEATURE_TASK_GENERATERESOURCES</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_TASKHOST</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_THREAD_ABORT</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_THREAD_CULTURE</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_THREAD_PRIORITY</DefineConstants>

Просмотреть файл

@ -105,6 +105,7 @@
<Compile Include="..\Shared\CopyOnWriteDictionary.cs" />
<Compile Include="..\Shared\IKeyed.cs" />
<Compile Include="..\Shared\MSBuildNameIgnoreCaseComparer.cs" />
<Compile Include="..\Shared\NamedPipeUtil.cs" />
<Compile Include="..\Shared\ReadOnlyEmptyCollection.cs" />
<Compile Include="..\Shared\ReadOnlyEmptyDictionary.cs" />
<Compile Include="..\Shared\NativeMethodsShared.cs">

Просмотреть файл

@ -16,10 +16,9 @@ namespace Microsoft.Build.CommandLine
/// <summary>
/// Instantiates an endpoint to act as a client
/// </summary>
/// <param name="pipeName">The name of the pipe to which we should connect.</param>
internal NodeEndpointOutOfProcTaskHost(string pipeName)
internal NodeEndpointOutOfProcTaskHost()
{
InternalConstruct(pipeName);
InternalConstruct();
}
#endregion // Constructors and Factories

Просмотреть файл

@ -612,9 +612,7 @@ namespace Microsoft.Build.CommandLine
// Snapshot the current environment
_savedEnvironment = CommunicationsUtilities.GetEnvironmentVariables();
string pipeName = "MSBuild" + Process.GetCurrentProcess().Id;
_nodeEndpoint = new NodeEndpointOutOfProcTaskHost(pipeName);
_nodeEndpoint = new NodeEndpointOutOfProcTaskHost();
_nodeEndpoint.OnLinkStatusChanged += new LinkStatusChangedDelegate(OnLinkStatusChanged);
_nodeEndpoint.Listen(this);

Просмотреть файл

@ -108,6 +108,7 @@
<Compile Include="..\Shared\Modifiers.cs">
<Link>Modifiers.cs</Link>
</Compile>
<Compile Include="..\Shared\NamedPipeUtil.cs" />
<Compile Include="..\Shared\NativeMethodsShared.cs">
<Link>NativeMethodsShared.cs</Link>
</Compile>

Просмотреть файл

@ -60,7 +60,12 @@ namespace Microsoft.Build.Internal
/// <summary>
/// Building with administrator privileges
/// </summary>
Administrator = 32
Administrator = 32,
/// <summary>
/// Using the .NET Core/.NET 5.0+ runtime
/// </summary>
NET = 64,
}
internal readonly struct Handshake
@ -75,7 +80,7 @@ namespace Microsoft.Build.Internal
internal Handshake(HandshakeOptions nodeType)
{
// We currently use 6 bits of this 32-bit integer. Very old builds will instantly reject any handshake that does not start with F5 or 06; slightly old builds always lead with 00.
// We currently use 7 bits of this 32-bit integer. Very old builds will instantly reject any handshake that does not start with F5 or 06; slightly old builds always lead with 00.
// This indicates in the first byte that we are a modern build.
options = (int)nodeType | (((int)CommunicationsUtilities.handshakeVersion) << 24);
string handshakeSalt = Environment.GetEnvironmentVariable("MSBUILDNODEHANDSHAKESALT");
@ -492,7 +497,23 @@ namespace Microsoft.Build.Internal
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.");
clrVersion = runtimeVersion.Equals(XMakeAttributes.MSBuildRuntimeValues.clr4, StringComparison.OrdinalIgnoreCase) ? 4 : 2;
if (runtimeVersion.Equals(XMakeAttributes.MSBuildRuntimeValues.clr2, StringComparison.OrdinalIgnoreCase))
{
clrVersion = 2;
}
else if (runtimeVersion.Equals(XMakeAttributes.MSBuildRuntimeValues.clr4, StringComparison.OrdinalIgnoreCase))
{
clrVersion = 4;
}
else if (runtimeVersion.Equals(XMakeAttributes.MSBuildRuntimeValues.net, StringComparison.OrdinalIgnoreCase))
{
clrVersion = 5;
}
else
{
ErrorUtilities.ThrowInternalErrorUnreachable();
}
is64Bit = architecture.Equals(XMakeAttributes.MSBuildArchitectureValues.x64);
}
}
@ -501,10 +522,26 @@ namespace Microsoft.Build.Internal
{
context |= HandshakeOptions.X64;
}
if (clrVersion == 2)
switch (clrVersion)
{
context |= HandshakeOptions.CLR2;
case 0:
// Not a taskhost, runtime must match
case 4:
// Default for MSBuild running on .NET Framework 4,
// not represented in handshake
break;
case 2:
context |= HandshakeOptions.CLR2;
break;
case >= 5:
context |= HandshakeOptions.NET;
break;
default:
ErrorUtilities.ThrowInternalErrorUnreachable();
break;
}
if (nodeReuse)
{
context |= HandshakeOptions.NodeReuse;

Просмотреть файл

@ -1,15 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics;
using System.IO;
#nullable enable
namespace Microsoft.Build.Shared
{
internal static class NamedPipeUtil
{
internal static string GetPipeNameOrPath(string pipeName)
internal static string GetPipeNameOrPath(int? processId = null)
{
if (processId is null)
{
processId = Process.GetCurrentProcess().Id;
}
string pipeName = $"MSBuild{processId}";
if (NativeMethodsShared.IsUnixLike)
{
// If we're on a Unix machine then named pipes are implemented using Unix Domain Sockets.

Просмотреть файл

@ -183,11 +183,8 @@ namespace Microsoft.Build.BackEnd
/// <summary>
/// Instantiates an endpoint to act as a client
/// </summary>
/// <param name="pipeName">The name of the pipe to which we should connect.</param>
internal void InternalConstruct(string pipeName)
internal void InternalConstruct()
{
ErrorUtilities.VerifyThrowArgumentLength(pipeName, nameof(pipeName));
_status = LinkStatus.Inactive;
_asyncDataMonitor = new object();
_sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer();
@ -195,6 +192,8 @@ namespace Microsoft.Build.BackEnd
_packetStream = new MemoryStream();
_binaryWriter = new BinaryWriter(_packetStream);
string pipeName = NamedPipeUtil.GetPipeNameOrPath();
#if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR
if (!NativeMethodsShared.IsMono)
{

Просмотреть файл

@ -2,6 +2,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Build.Shared;
using Shouldly;
using Xunit;
namespace Microsoft.Build.UnitTests
@ -47,35 +49,82 @@ namespace Microsoft.Build.UnitTests
public void TestRuntimeValuesMatch()
{
Assert.True(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.any, XMakeAttributes.MSBuildRuntimeValues.currentRuntime));
Assert.True(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.any, XMakeAttributes.MSBuildRuntimeValues.net));
Assert.True(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.any, XMakeAttributes.MSBuildRuntimeValues.clr4));
Assert.True(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.clr2, XMakeAttributes.MSBuildRuntimeValues.any));
#if NET5_0_OR_GREATER
Assert.True(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.currentRuntime, XMakeAttributes.MSBuildRuntimeValues.net));
#else
Assert.True(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.currentRuntime, XMakeAttributes.MSBuildRuntimeValues.clr4));
#endif
// Never true
Assert.False(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.currentRuntime, XMakeAttributes.MSBuildRuntimeValues.clr2));
Assert.False(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.clr4, XMakeAttributes.MSBuildRuntimeValues.clr2));
Assert.False(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.clr4, XMakeAttributes.MSBuildRuntimeValues.net));
Assert.False(XMakeAttributes.RuntimeValuesMatch(XMakeAttributes.MSBuildRuntimeValues.clr2, XMakeAttributes.MSBuildRuntimeValues.net));
}
[Theory]
[InlineData(XMakeAttributes.MSBuildRuntimeValues.any, XMakeAttributes.MSBuildRuntimeValues.clr4, true, XMakeAttributes.MSBuildRuntimeValues.clr4)]
[InlineData(XMakeAttributes.MSBuildRuntimeValues.clr4, XMakeAttributes.MSBuildRuntimeValues.any, true, XMakeAttributes.MSBuildRuntimeValues.clr4)]
[InlineData(XMakeAttributes.MSBuildRuntimeValues.clr2, XMakeAttributes.MSBuildRuntimeValues.any, true, XMakeAttributes.MSBuildRuntimeValues.clr2)]
[InlineData(XMakeAttributes.MSBuildRuntimeValues.currentRuntime, XMakeAttributes.MSBuildRuntimeValues.clr2, false, null)]
[InlineData(XMakeAttributes.MSBuildRuntimeValues.clr4, XMakeAttributes.MSBuildRuntimeValues.clr2, false, null)]
public void TestMergeRuntimeValues(string left, string right, bool success, string expected)
{
XMakeAttributes.TryMergeRuntimeValues(left, right, out string mergedRuntime)
.ShouldBe(success);
mergedRuntime.ShouldBe(expected);
}
[Fact]
public void TestMergeRuntimeValues()
public void TestMergeRuntimeValuesAnyAcceptsCurrent()
{
string mergedRuntime;
Assert.True(XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.any, XMakeAttributes.MSBuildRuntimeValues.currentRuntime, out mergedRuntime));
Assert.Equal(XMakeAttributes.MSBuildRuntimeValues.clr4, mergedRuntime);
XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.any,
XMakeAttributes.MSBuildRuntimeValues.currentRuntime,
out string mergedRuntime)
.ShouldBeTrue();
Assert.True(XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.any, XMakeAttributes.MSBuildRuntimeValues.clr4, out mergedRuntime));
Assert.Equal(XMakeAttributes.MSBuildRuntimeValues.clr4, mergedRuntime);
mergedRuntime.ShouldBe(XMakeAttributes.GetCurrentMSBuildRuntime());
}
Assert.True(XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.clr2, XMakeAttributes.MSBuildRuntimeValues.any, out mergedRuntime));
Assert.Equal(XMakeAttributes.MSBuildRuntimeValues.clr2, mergedRuntime);
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp,
"Tests whether 'current' merges with 'clr4' which is true only on Framework")]
public void TestMergeRuntimeValuesCurrentToClr4()
{
XMakeAttributes.TryMergeRuntimeValues(
XMakeAttributes.MSBuildRuntimeValues.currentRuntime,
XMakeAttributes.MSBuildRuntimeValues.clr4,
out string mergedRuntime).ShouldBeTrue();
mergedRuntime.ShouldBe(XMakeAttributes.MSBuildRuntimeValues.clr4);
Assert.True(XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.currentRuntime, XMakeAttributes.MSBuildRuntimeValues.clr4, out mergedRuntime));
Assert.Equal(XMakeAttributes.MSBuildRuntimeValues.clr4, mergedRuntime);
XMakeAttributes.TryMergeRuntimeValues(
XMakeAttributes.MSBuildRuntimeValues.currentRuntime,
XMakeAttributes.MSBuildRuntimeValues.net,
out mergedRuntime).ShouldBeFalse();
mergedRuntime.ShouldBeNull();
}
Assert.False(XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.currentRuntime, XMakeAttributes.MSBuildRuntimeValues.clr2, out mergedRuntime));
Assert.Null(mergedRuntime);
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework,
"Tests whether 'current' merges with 'net' which is true only on core")]
public void TestMergeRuntimeValuesCurrentToCore()
{
XMakeAttributes.TryMergeRuntimeValues(
XMakeAttributes.MSBuildRuntimeValues.currentRuntime,
XMakeAttributes.MSBuildRuntimeValues.net,
out string mergedRuntime).ShouldBeTrue();
mergedRuntime.ShouldBe(XMakeAttributes.MSBuildRuntimeValues.net);
Assert.False(XMakeAttributes.TryMergeRuntimeValues(XMakeAttributes.MSBuildRuntimeValues.clr4, XMakeAttributes.MSBuildRuntimeValues.clr2, out mergedRuntime));
Assert.Null(mergedRuntime);
XMakeAttributes.TryMergeRuntimeValues(
XMakeAttributes.MSBuildRuntimeValues.currentRuntime,
XMakeAttributes.MSBuildRuntimeValues.clr4,
out mergedRuntime).ShouldBeFalse();
mergedRuntime.ShouldBeNull();
}
[Fact]

Просмотреть файл

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Microsoft.Build.Shared
{
@ -76,6 +77,7 @@ namespace Microsoft.Build.Shared
internal const string clr2 = "CLR2";
internal const string clr4 = "CLR4";
internal const string currentRuntime = "CurrentRuntime";
internal const string net = "NET";
internal const string any = "*";
}
@ -99,7 +101,7 @@ namespace Microsoft.Build.Shared
private static readonly HashSet<string> KnownBatchingTargetAttributes = new HashSet<string> { name, condition, dependsOnTargets, beforeTargets, afterTargets };
private static readonly HashSet<string> ValidMSBuildRuntimeValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { MSBuildRuntimeValues.clr2, MSBuildRuntimeValues.clr4, MSBuildRuntimeValues.currentRuntime, MSBuildRuntimeValues.any };
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 };
@ -179,10 +181,10 @@ namespace Microsoft.Build.Shared
return true;
}
if ((runtimeA.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase) && runtimeB.Equals(MSBuildRuntimeValues.clr4, StringComparison.OrdinalIgnoreCase)) ||
(runtimeA.Equals(MSBuildRuntimeValues.clr4, StringComparison.OrdinalIgnoreCase) && runtimeB.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase)))
if ((runtimeA.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase) && runtimeB.Equals(GetCurrentMSBuildRuntime(), StringComparison.OrdinalIgnoreCase)) ||
(runtimeA.Equals(GetCurrentMSBuildRuntime(), StringComparison.OrdinalIgnoreCase) && runtimeB.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase)))
{
// CLR4 is the current runtime, so this is also a match.
// Matches the current runtime, so match.
return true;
}
@ -216,13 +218,15 @@ namespace Microsoft.Build.Shared
runtimeB = MSBuildRuntimeValues.any;
}
string actualCurrentRuntime = GetCurrentMSBuildRuntime();
// if they're equal, then there's no problem -- just return the equivalent runtime.
if (runtimeA.Equals(runtimeB, StringComparison.OrdinalIgnoreCase))
{
if (runtimeA.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase) ||
runtimeA.Equals(MSBuildRuntimeValues.any, StringComparison.OrdinalIgnoreCase))
{
mergedRuntime = MSBuildRuntimeValues.clr4;
mergedRuntime = actualCurrentRuntime;
}
else
{
@ -232,21 +236,22 @@ namespace Microsoft.Build.Shared
return true;
}
// if both A and B are one of CLR4, don't care, or current, then the end result will be CLR4 no matter what.
// if both A and B are one of actual-current-runtime, don't care or current,
// then the end result will be current-runtime no matter what.
if (
(
runtimeA.Equals(MSBuildRuntimeValues.clr4, StringComparison.OrdinalIgnoreCase) ||
runtimeA.Equals(actualCurrentRuntime, StringComparison.OrdinalIgnoreCase) ||
runtimeA.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase) ||
runtimeA.Equals(MSBuildRuntimeValues.any, StringComparison.OrdinalIgnoreCase)
) &&
(
runtimeB.Equals(MSBuildRuntimeValues.clr4, StringComparison.OrdinalIgnoreCase) ||
runtimeB.Equals(actualCurrentRuntime, StringComparison.OrdinalIgnoreCase) ||
runtimeB.Equals(MSBuildRuntimeValues.currentRuntime, StringComparison.OrdinalIgnoreCase) ||
runtimeB.Equals(MSBuildRuntimeValues.any, StringComparison.OrdinalIgnoreCase)
)
)
{
mergedRuntime = MSBuildRuntimeValues.clr4;
mergedRuntime = actualCurrentRuntime;
return true;
}
@ -320,8 +325,8 @@ namespace Microsoft.Build.Shared
MSBuildRuntimeValues.any.Equals(runtime, StringComparison.OrdinalIgnoreCase) ||
MSBuildRuntimeValues.currentRuntime.Equals(runtime, StringComparison.OrdinalIgnoreCase))
{
// Default to CLR4.
return MSBuildRuntimeValues.clr4;
// Default to current.
return GetCurrentMSBuildRuntime();
}
else
{
@ -425,6 +430,18 @@ namespace Microsoft.Build.Shared
return currentArchitecture;
}
/// <summary>
/// Returns the MSBuildRuntime value corresponding to the current process' runtime.
/// </summary>
internal static string GetCurrentMSBuildRuntime()
{
#if NET40_OR_GREATER
return MSBuildRuntimeValues.clr4;
#else
return MSBuildRuntimeValues.net;
#endif
}
/// <summary>
/// Given an MSBuildArchitecture value that may be non-explicit -- e.g. "CurrentArchitecture" or "Any" --
/// return the specific MSBuildArchitecture value that it would map to in this case. If it does not map

Просмотреть файл

@ -122,8 +122,9 @@
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateLauncher" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateResource" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateResource" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR4" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateResource" AssemblyName="Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR2" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateResource" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR4" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' != 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateResource" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="NET" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' == 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateResource" AssemblyName="Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR2" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' != 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.GenerateTrustInfo" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.GetAssemblyIdentity" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
@ -141,8 +142,8 @@
<UsingTask TaskName="Microsoft.Build.Tasks.ReadLinesFromFile" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.RegisterAssembly" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.RegisterAssembly" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR4" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.RegisterAssembly" AssemblyName="Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR2" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.RegisterAssembly" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR4" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' != 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.RegisterAssembly" AssemblyName="Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR2" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' != 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.RemoveDir" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.RemoveDuplicates" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
@ -164,8 +165,8 @@
<UsingTask TaskName="Microsoft.Build.Tasks.Touch" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.UnregisterAssembly" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.UnregisterAssembly" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR4" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.UnregisterAssembly" AssemblyName="Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR2" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.UnregisterAssembly" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR4" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' != 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.UnregisterAssembly" AssemblyName="Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Runtime="CLR2" Condition="('$(MSBuildAssemblyVersion)' != '') and '$(DisableOutOfProcTaskHost)' == '' and '$(MSBuildRuntimeType)' != 'Core'" />
<UsingTask TaskName="Microsoft.Build.Tasks.UpdateManifest" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />
<UsingTask TaskName="Microsoft.Build.Tasks.Unzip" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition="'$(MSBuildAssemblyVersion)' != ''" />