diff --git a/eng/Packages.props b/eng/Packages.props
index b6e51805983..7334fbeb8d7 100644
--- a/eng/Packages.props
+++ b/eng/Packages.props
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj b/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj
index 95001217b5d..8ddca6108ac 100644
--- a/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj
+++ b/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj
@@ -36,9 +36,9 @@
TargetFramework=$(FullFrameworkTFM)
TargetFramework=$(FullFrameworkTFM)
- TargetFramework=netstandard2.0
+ TargetFramework=net6.0
-
+
TargetFramework=$(FullFrameworkTFM)
diff --git a/src/Directory.BeforeCommon.targets b/src/Directory.BeforeCommon.targets
index 81b11a5b4ed..e238270ae6a 100644
--- a/src/Directory.BeforeCommon.targets
+++ b/src/Directory.BeforeCommon.targets
@@ -82,7 +82,7 @@
true
- $(DefineConstants);RUNTIME_TYPE_NETCORE
+ $(DefineConstants);RUNTIME_TYPE_NETCORE;FEATURE_FASTSPAN
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index dad17637aba..de2ef19eb31 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -15,6 +15,9 @@
true
+
+
+ $(NoWarn);NU5131
false
@@ -27,8 +30,9 @@
AnyCPU;x64
- $(FullFrameworkTFM);netstandard2.0
- $(FullFrameworkTFM)
+ $(FullFrameworkTFM);net6.0;netstandard2.0
+ net6.0;netstandard2.0
+ $(FullFrameworkTFM);netstandard2.0
AnyCPU
@@ -71,4 +75,34 @@
AnyCPU
+
+
+ $(TargetsForTfmSpecificContentInPackage);ShipRefAssembliesToNuGetPackage
+
+
+
+
+
+ true
+ false
+ false
+ $(TargetsForTfmSpecificContentInPackage);ShipRefAssembliesToNuGetPackage
+ false
+
+
+ false
+
+
+
+
+
+
+ ref\$(TargetFramework)
+
+
+
+ ref\$(TargetFramework)
+
+
+
diff --git a/src/Framework/NativeMethods.cs b/src/Framework/NativeMethods.cs
index 9c3a8dbaec5..a838e0dc9a6 100644
--- a/src/Framework/NativeMethods.cs
+++ b/src/Framework/NativeMethods.cs
@@ -9,6 +9,7 @@
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
using System.Text;
using System.Threading;
@@ -21,9 +22,10 @@
#nullable disable
namespace Microsoft.Build.Framework;
+
internal static class NativeMethods
{
- #region Constants
+#region Constants
internal const uint ERROR_INSUFFICIENT_BUFFER = 0x8007007A;
internal const uint STARTUP_LOADER_SAFEMODE = 0x10;
@@ -71,9 +73,9 @@ internal static class NativeMethods
internal const uint WAIT_OBJECT_0 = 0x00000000;
internal const uint WAIT_TIMEOUT = 0x00000102;
- #endregion
+#endregion
- #region Enums
+#region Enums
private enum PROCESSINFOCLASS : int
{
@@ -198,9 +200,9 @@ internal enum ProcessorArchitectures
Unknown
}
- #endregion
+#endregion
- #region Structs
+#region Structs
///
/// Structure that contain information about the system on which we are running
@@ -568,9 +570,9 @@ private unsafe static int GetLogicalCoreCountOnWindows()
return -1;
}
- #endregion
+#endregion
- #region Member data
+#region Member data
internal static bool HasMaxPath => MaxPath == MAX_PATH;
@@ -709,10 +711,10 @@ internal static bool IsMono
#if !CLR2COMPATIBILITY
private static bool? _isWindows;
#endif
-
///
/// Gets a flag indicating if we are running under some version of Windows
///
+ [SupportedOSPlatformGuard("windows")]
internal static bool IsWindows
{
#if CLR2COMPATIBILITY
@@ -867,9 +869,9 @@ private static SystemInformationData SystemInformation
///
internal static ProcessorArchitectures ProcessorArchitectureNative => SystemInformation.ProcessorArchitectureTypeNative;
- #endregion
+#endregion
- #region Wrapper methods
+#region Wrapper methods
///
/// Really truly non pumping wait.
@@ -1451,9 +1453,9 @@ internal static void VerifyThrowWin32Result(int result)
}
}
- #endregion
+#endregion
- #region PInvoke
+#region PInvoke
///
/// Gets the current OEM code page which is used by console apps
@@ -1609,9 +1611,9 @@ out FILETIME lpLastWriteTime
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetThreadErrorMode(int newMode, out int oldMode);
- #endregion
+#endregion
- #region Extensions
+#region Extensions
///
/// Waits while pumping APC messages. This is important if the waiting thread is an STA thread which is potentially
@@ -1654,9 +1656,9 @@ internal static bool MsgWaitOne(this WaitHandle handle, int timeout)
return returnValue == 0;
}
- #endregion
+#endregion
- #region helper methods
+#region helper methods
internal static bool DirectoryExists(string fullPath)
{
@@ -1699,6 +1701,6 @@ internal static bool FileOrDirectoryExistsWindows(string path)
return GetFileAttributesEx(path, 0, ref data);
}
- #endregion
+#endregion
}
diff --git a/src/Framework/README.md b/src/Framework/README.md
index 32c4e063b2b..1b72454f526 100644
--- a/src/Framework/README.md
+++ b/src/Framework/README.md
@@ -4,3 +4,8 @@ This package contains `Microsoft.Build.Framework.dll`, which defines [fundamenta
The items in this namespace are primarily base-level classes and interfaces shared across MSBuild's object model. MSBuild task or extension developers can reference this package to implement interfaces such as
[`ITask`](https://docs.microsoft.com/dotnet/api/microsoft.build.framework.itask), and [`ILogger`](https://docs.microsoft.com/dotnet/api/microsoft.build.framework.ilogger).
+
+### netstandard2.0 target
+The `netstandard2.0` target of this build is configured only to output reference assemblies; at runtime MSBuild will be `net6.0` or `net472`. Please use the `net6.0`-targeted assemblies for .NET Core 6+ scenarios.
+
+For context, see https://github.com/dotnet/msbuild/pull/6148
\ No newline at end of file
diff --git a/src/Framework/Sdk/SdkResultItem.cs b/src/Framework/Sdk/SdkResultItem.cs
index cff07bb8bf7..febbbeffabc 100644
--- a/src/Framework/Sdk/SdkResultItem.cs
+++ b/src/Framework/Sdk/SdkResultItem.cs
@@ -36,7 +36,7 @@ public SdkResultItem(string itemSpec, Dictionary? metadata)
Metadata = metadata;
}
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (obj is SdkResultItem item &&
ItemSpec == item.ItemSpec &&
diff --git a/src/Framework/SupportedOSPlatform.cs b/src/Framework/SupportedOSPlatform.cs
new file mode 100644
index 00000000000..8a50d7c82f0
--- /dev/null
+++ b/src/Framework/SupportedOSPlatform.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#if !NET6_0_OR_GREATER
+namespace System.Runtime.Versioning
+{
+ ///
+ /// SupportedOSPlatform is a net5.0+ Attribute.
+ /// Create the same type only in full-framework and netstandard2.0 builds
+ /// to prevent many #if RUNTIME_TYPE_NETCORE checks.
+ ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
+ internal class SupportedOSPlatformGuard : Attribute
+ {
+ internal SupportedOSPlatformGuard(string platformName)
+ {
+ }
+ }
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Class)]
+ internal class SupportedOSPlatform : Attribute
+ {
+ internal SupportedOSPlatform(string platformName)
+ {
+ }
+ }
+}
+#endif
diff --git a/src/MSBuild/MSBuild.csproj b/src/MSBuild/MSBuild.csproj
index 803083dd1fc..337e3260d18 100644
--- a/src/MSBuild/MSBuild.csproj
+++ b/src/MSBuild/MSBuild.csproj
@@ -211,6 +211,13 @@
+
+
+
+ [2.0.3]
+
+
diff --git a/src/MSBuildTaskHost/MSBuildTaskHost.csproj b/src/MSBuildTaskHost/MSBuildTaskHost.csproj
index f56435ec284..e7dba840e1a 100644
--- a/src/MSBuildTaskHost/MSBuildTaskHost.csproj
+++ b/src/MSBuildTaskHost/MSBuildTaskHost.csproj
@@ -142,6 +142,9 @@
StringBuilderCache.cs
+
+ SupportedOSPlatform.cs
+
TaskEngineAssemblyResolver.cs
diff --git a/src/Samples/PortableTask/PortableTask.csproj b/src/Samples/PortableTask/PortableTask.csproj
index 6a4541787a1..a497a305fb2 100644
--- a/src/Samples/PortableTask/PortableTask.csproj
+++ b/src/Samples/PortableTask/PortableTask.csproj
@@ -3,7 +3,7 @@
true
false
false
- netstandard2.0
+ netstandard2.0
diff --git a/src/StringTools/InternableString.cs b/src/StringTools/InternableString.cs
index 302d50bfd6c..f04d2a9e931 100644
--- a/src/StringTools/InternableString.cs
+++ b/src/StringTools/InternableString.cs
@@ -96,7 +96,7 @@ public bool MoveNext()
///
private readonly ReadOnlySpan _inlineSpan;
-#if NETSTANDARD
+#if FEATURE_FASTSPAN
///
/// .NET Core does not keep a reference to the containing object in . In particular,
/// it cannot recover the string if the span represents one. We have to hold the reference separately to be able to
@@ -122,7 +122,7 @@ internal InternableString(ReadOnlySpan span)
_inlineSpan = span;
_spans = null;
Length = span.Length;
-#if NETSTANDARD
+#if FEATURE_FASTSPAN
_inlineSpanString = null;
#endif
}
@@ -141,7 +141,7 @@ internal InternableString(string str)
_inlineSpan = str.AsSpan();
_spans = null;
Length = str.Length;
-#if NETSTANDARD
+#if FEATURE_FASTSPAN
_inlineSpanString = str;
#endif
}
@@ -154,7 +154,7 @@ internal InternableString(SpanBasedStringBuilder stringBuilder)
_inlineSpan = default(ReadOnlySpan);
_spans = stringBuilder.Spans;
Length = stringBuilder.Length;
-#if NETSTANDARD
+#if FEATURE_FASTSPAN
_inlineSpanString = null;
#endif
}
@@ -220,7 +220,7 @@ public unsafe string ExpensiveConvertToString()
// Special case: if we hold just one string, we can directly return it.
if (_inlineSpan.Length == Length)
{
-#if NETSTANDARD
+#if FEATURE_FASTSPAN
if (_inlineSpanString != null)
{
return _inlineSpanString;
diff --git a/src/StringTools/WeakStringCache.Concurrent.cs b/src/StringTools/WeakStringCache.Concurrent.cs
index 6110475e946..3261141fcbf 100644
--- a/src/StringTools/WeakStringCache.Concurrent.cs
+++ b/src/StringTools/WeakStringCache.Concurrent.cs
@@ -32,7 +32,7 @@ public string GetOrCreateEntry(ref InternableString internable, out bool cacheHi
{
int hashCode = internable.GetHashCode();
- StringWeakHandle handle;
+ StringWeakHandle? handle;
string? result;
// Get the existing handle from the cache and lock it while we're dereferencing it to prevent a race with the Scavenge
@@ -98,7 +98,7 @@ public void Scavenge()
foreach (KeyValuePair entry in _stringsByHashCode)
{
// We can safely dereference entry.Value as the caller guarantees that Scavenge runs only on one thread.
- if (!entry.Value.IsUsed && _stringsByHashCode.TryRemove(entry.Key, out StringWeakHandle removedHandle))
+ if (!entry.Value.IsUsed && _stringsByHashCode.TryRemove(entry.Key, out StringWeakHandle? removedHandle))
{
lock (removedHandle)
{
diff --git a/src/Tasks.UnitTests/AssemblyDependency/Miscellaneous.cs b/src/Tasks.UnitTests/AssemblyDependency/Miscellaneous.cs
index 9fe18eaef93..beec4a1d226 100644
--- a/src/Tasks.UnitTests/AssemblyDependency/Miscellaneous.cs
+++ b/src/Tasks.UnitTests/AssemblyDependency/Miscellaneous.cs
@@ -14,7 +14,6 @@
using SystemProcessorArchitecture = System.Reflection.ProcessorArchitecture;
using Xunit.Abstractions;
using Shouldly;
-using System.Text;
#nullable disable
diff --git a/src/Tasks.UnitTests/Microsoft.Build.Tasks.UnitTests.csproj b/src/Tasks.UnitTests/Microsoft.Build.Tasks.UnitTests.csproj
index 9d9813898bc..4bf53a812a9 100644
--- a/src/Tasks.UnitTests/Microsoft.Build.Tasks.UnitTests.csproj
+++ b/src/Tasks.UnitTests/Microsoft.Build.Tasks.UnitTests.csproj
@@ -25,7 +25,7 @@
-
+
diff --git a/src/Tasks/BootstrapperUtil/BootstrapperBuilder.cs b/src/Tasks/BootstrapperUtil/BootstrapperBuilder.cs
index 39469981e66..b8960252b8a 100644
--- a/src/Tasks/BootstrapperUtil/BootstrapperBuilder.cs
+++ b/src/Tasks/BootstrapperUtil/BootstrapperBuilder.cs
@@ -17,6 +17,7 @@
using System.Xml.XPath;
using System.Xml.Xsl;
using Microsoft.Build.Shared.FileSystem;
+using System.Runtime.Versioning;
#nullable disable
@@ -28,6 +29,7 @@ namespace Microsoft.Build.Tasks.Deployment.Bootstrapper
[ComVisible(true)]
[Guid("1D9FE38A-0226-4b95-9C6B-6DFFA2236270")]
[ClassInterface(ClassInterfaceType.None)]
+ [SupportedOSPlatform("windows")]
public class BootstrapperBuilder : IBootstrapperBuilder
{
private static readonly bool s_logging = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("VSPLOG"));
@@ -1643,7 +1645,7 @@ private static string GetFileHash(string filePath)
// the .NET Framework we are targeting. In ideal situations, bootstrapper files will be
// pre-signed anwyay; this is a fallback in case we ever encounter a bootstrapper that is
// not signed.
- System.Security.Cryptography.SHA256CryptoServiceProvider sha = new System.Security.Cryptography.SHA256CryptoServiceProvider();
+ System.Security.Cryptography.SHA256 sha = System.Security.Cryptography.SHA256.Create("System.Security.Cryptography.SHA256CryptoServiceProvider");
using (Stream s = fi.OpenRead())
{
@@ -1906,7 +1908,7 @@ private static XmlElement CreateApplicationElement(XmlElement configElement, Bui
XmlElement filesNode = applicationElement.OwnerDocument.CreateElement("Files");
XmlElement fileNode = filesNode.OwnerDocument.CreateElement("File");
AddAttribute(fileNode, "Name", settings.ApplicationFile);
- AddAttribute(fileNode, URLNAME_ATTRIBUTE, Uri.EscapeUriString(settings.ApplicationFile));
+ AddAttribute(fileNode, URLNAME_ATTRIBUTE, Uri.EscapeDataString(settings.ApplicationFile));
filesNode.AppendChild(fileNode);
applicationElement.AppendChild(filesNode);
}
diff --git a/src/Tasks/BootstrapperUtil/Util.cs b/src/Tasks/BootstrapperUtil/Util.cs
index 0ed5be1dea0..d62c8247070 100644
--- a/src/Tasks/BootstrapperUtil/Util.cs
+++ b/src/Tasks/BootstrapperUtil/Util.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Runtime.Versioning;
using Microsoft.Build.Shared;
using Microsoft.Win32;
@@ -75,6 +76,7 @@ public static CultureInfo GetCultureInfoFromString(string cultureName)
public static CultureInfo DefaultCultureInfo => System.Threading.Thread.CurrentThread.CurrentUICulture;
+ [SupportedOSPlatform("windows")]
// This is the 4.0 property and will always point to the Dev10 registry key so that we don't break backwards compatibility.
// Applications relying on 4.5 will need to use the new method that is introduced in 4.5.
public static string DefaultPath
@@ -102,6 +104,7 @@ public static string DefaultPath
}
}
+ [SupportedOSPlatform("windows")]
// A new method in 4.5 to get the default path for bootstrapper packages.
// This method is not going to cache the path as it could be different depending on the Visual Studio version.
public static string GetDefaultPath(string visualStudioVersion)
@@ -153,6 +156,7 @@ public static string GetDefaultPath(string visualStudioVersion)
return Directory.GetCurrentDirectory();
}
+ [SupportedOSPlatform("windows")]
// Gets the list of additional paths to inspect for packages as defined in the registry
public static List AdditionalPackagePaths
{
@@ -202,6 +206,7 @@ public static List AdditionalPackagePaths
}
}
+ [SupportedOSPlatform("windows")]
private static string ReadRegistryString(RegistryKey key, string path, string registryValue)
{
RegistryKey subKey = key.OpenSubKey(path, false);
diff --git a/src/Tasks/DownloadFile.cs b/src/Tasks/DownloadFile.cs
index c55eedb3974..5192719aa13 100644
--- a/src/Tasks/DownloadFile.cs
+++ b/src/Tasks/DownloadFile.cs
@@ -146,11 +146,17 @@ private async Task DownloadAsync(Uri uri, CancellationToken cancellationToken)
{
response.EnsureSuccessStatusCode();
}
+#if NET6_0_OR_GREATER
+ catch (HttpRequestException)
+ {
+ throw;
+#else
catch (HttpRequestException e)
{
- // HttpRequestException does not have the status code so its wrapped and thrown here so that later on we can determine
- // if a retry is possible based on the status code
+ // MSBuild History: CustomHttpRequestException was created as a wrapper over HttpRequestException
+ // so it could include the StatusCode. As of net5.0, the statuscode is now in HttpRequestException.
throw new CustomHttpRequestException(e.Message, e.InnerException, response.StatusCode);
+#endif
}
if (!TryGetFileName(response, out string filename))
@@ -181,7 +187,11 @@ private async Task DownloadAsync(Uri uri, CancellationToken cancellationToken)
{
Log.LogMessageFromResources(MessageImportance.High, "DownloadFile.Downloading", SourceUrl, destinationFile.FullName, response.Content.Headers.ContentLength);
- using (Stream responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
+ using (Stream responseStream = await response.Content.ReadAsStreamAsync(
+#if NET6_0_OR_GREATER
+ cancellationToken
+#endif
+ ).ConfigureAwait(false))
{
await responseStream.CopyToAsync(target, 1024, cancellationToken).ConfigureAwait(false);
}
@@ -220,20 +230,34 @@ private static bool IsRetriable(Exception exception, out Exception actualExcepti
}
// Some HttpRequestException have an inner exception that has the real error
- if (actualException is HttpRequestException httpRequestException && httpRequestException.InnerException != null)
+ if (actualException is HttpRequestException httpRequestException)
{
- actualException = httpRequestException.InnerException;
+ if (httpRequestException.InnerException != null)
+ {
+ actualException = httpRequestException.InnerException;
- // An IOException inside of a HttpRequestException means that something went wrong while downloading
- if (actualException is IOException)
+ // An IOException inside of a HttpRequestException means that something went wrong while downloading
+ if (actualException is IOException)
+ {
+ return true;
+ }
+ }
+
+#if NET6_0_OR_GREATER
+ // net5.0 included StatusCode in the HttpRequestException.
+ switch (httpRequestException.StatusCode)
{
- return true;
+ case HttpStatusCode.InternalServerError:
+ case HttpStatusCode.RequestTimeout:
+ return true;
}
}
+#else
+ }
+ // framework workaround for HttpRequestException not containing StatusCode
if (actualException is CustomHttpRequestException customHttpRequestException)
{
- // A wrapped CustomHttpRequestException has the status code from the error
switch (customHttpRequestException.StatusCode)
{
case HttpStatusCode.InternalServerError:
@@ -241,6 +265,7 @@ private static bool IsRetriable(Exception exception, out Exception actualExcepti
return true;
}
}
+#endif
if (actualException is WebException webException)
{
@@ -287,8 +312,10 @@ private bool TryGetFileName(HttpResponseMessage response, out string filename)
return !String.IsNullOrWhiteSpace(filename);
}
+#if !NET6_0_OR_GREATER
///
/// Represents a wrapper around the that also contains the .
+ /// DEPRECATED as of net5.0, which included the StatusCode in the HttpRequestException class.
///
private sealed class CustomHttpRequestException : HttpRequestException
{
@@ -300,6 +327,7 @@ public CustomHttpRequestException(string message, Exception inner, HttpStatusCod
public HttpStatusCode StatusCode { get; }
}
+#endif
private bool ShouldSkip(HttpResponseMessage response, FileInfo destinationFile)
{
diff --git a/src/Tasks/FormatUrl.cs b/src/Tasks/FormatUrl.cs
index f742f4d238b..4b600c49ef9 100644
--- a/src/Tasks/FormatUrl.cs
+++ b/src/Tasks/FormatUrl.cs
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#if !RUNTIME_TYPE_NETCORE
using System;
-using Microsoft.Build.Framework;
using Microsoft.Build.Tasks.Deployment.ManifestUtilities;
+#endif
+using Microsoft.Build.Framework;
#nullable disable
diff --git a/src/Tasks/GenerateApplicationManifest.cs b/src/Tasks/GenerateApplicationManifest.cs
index bece4016d94..a6361b25472 100644
--- a/src/Tasks/GenerateApplicationManifest.cs
+++ b/src/Tasks/GenerateApplicationManifest.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Globalization;
using System.IO;
+using System.Runtime.Versioning;
using System.Xml;
using Microsoft.Build.Framework;
@@ -17,6 +18,7 @@ namespace Microsoft.Build.Tasks
///
/// Generates an application manifest for ClickOnce projects.
///
+ [SupportedOSPlatform("windows")]
public sealed class GenerateApplicationManifest : GenerateManifestBase
{
private enum _ManifestType
@@ -108,6 +110,16 @@ public bool UseApplicationTrust
set => _useApplicationTrust = value;
}
+ public override bool Execute()
+ {
+ if (!NativeMethodsShared.IsWindows)
+ {
+ Log.LogErrorWithCodeFromResources("General.TaskRequiresWindows", nameof(GenerateApplicationManifest));
+ return false;
+ }
+ return base.Execute();
+ }
+
protected override Type GetObjectType()
{
return typeof(ApplicationManifest);
diff --git a/src/Tasks/GenerateDeploymentManifest.cs b/src/Tasks/GenerateDeploymentManifest.cs
index d4ff40421a4..6867f27717b 100644
--- a/src/Tasks/GenerateDeploymentManifest.cs
+++ b/src/Tasks/GenerateDeploymentManifest.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.IO;
using Microsoft.Build.Tasks.Deployment.ManifestUtilities;
+using System.Runtime.Versioning;
#nullable disable
@@ -13,6 +14,7 @@ namespace Microsoft.Build.Tasks
///
/// Generates a deploy manifest for ClickOnce projects.
///
+ [SupportedOSPlatform("windows")]
public sealed class GenerateDeploymentManifest : GenerateManifestBase
{
private bool? _createDesktopShortcut;
@@ -142,6 +144,7 @@ private bool BuildResolvedSettings(DeployManifest manifest)
else if (String.IsNullOrEmpty(manifest.Publisher))
{
string org = Util.GetRegisteredOrganization();
+
manifest.Publisher = !String.IsNullOrEmpty(org) ? org : manifest.Product;
}
Debug.Assert(!String.IsNullOrEmpty(manifest.Publisher));
@@ -149,6 +152,16 @@ private bool BuildResolvedSettings(DeployManifest manifest)
return true;
}
+ public override bool Execute()
+ {
+ if (!NativeMethodsShared.IsWindows)
+ {
+ Log.LogErrorWithCodeFromResources("General.TaskRequiresWindows", nameof(GenerateDeploymentManifest));
+ return false;
+ }
+ return base.Execute();
+ }
+
protected override Type GetObjectType()
{
return typeof(DeployManifest);
diff --git a/src/Tasks/GenerateLauncher.cs b/src/Tasks/GenerateLauncher.cs
index 6bedd918410..683736168cc 100644
--- a/src/Tasks/GenerateLauncher.cs
+++ b/src/Tasks/GenerateLauncher.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.Runtime.Versioning;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Tasks.Deployment.Bootstrapper;
@@ -16,6 +17,7 @@ namespace Microsoft.Build.Tasks
///
/// Generates a bootstrapper for ClickOnce deployment projects.
///
+ [SupportedOSPlatform("windows")]
public sealed class GenerateLauncher : TaskExtension
{
private const string LAUNCHER_EXE = "Launcher.exe";
@@ -39,6 +41,12 @@ public sealed class GenerateLauncher : TaskExtension
public override bool Execute()
{
+ if (!NativeMethodsShared.IsWindows)
+ {
+ Log.LogErrorWithCodeFromResources("General.TaskRequiresWindows", nameof(GenerateLauncher));
+ return false;
+ }
+
if (LauncherPath == null)
{
// Launcher lives next to ClickOnce bootstrapper.
@@ -57,17 +65,17 @@ public override bool Execute()
var launcherBuilder = new LauncherBuilder(LauncherPath);
string entryPointFileName = Path.GetFileName(EntryPoint.ItemSpec);
- //
+
// If the EntryPoint specified is apphost.exe or singlefilehost.exe, we need to replace the EntryPoint
// with the AssemblyName instead since apphost.exe/singlefilehost.exe is an intermediate file for
// for final published {assemblyname}.exe.
- //
if ((entryPointFileName.Equals(Constants.AppHostExe, StringComparison.InvariantCultureIgnoreCase) ||
entryPointFileName.Equals(Constants.SingleFileHostExe, StringComparison.InvariantCultureIgnoreCase)) &&
- !String.IsNullOrEmpty(AssemblyName))
+ !string.IsNullOrEmpty(AssemblyName))
{
entryPointFileName = AssemblyName;
}
+
BuildResults results = launcherBuilder.Build(entryPointFileName, OutputPath);
BuildMessage[] messages = results.Messages;
diff --git a/src/Tasks/GenerateManifestBase.cs b/src/Tasks/GenerateManifestBase.cs
index 65ea58c62b0..ef8aed08163 100644
--- a/src/Tasks/GenerateManifestBase.cs
+++ b/src/Tasks/GenerateManifestBase.cs
@@ -272,6 +272,12 @@ private AssemblyIdentity CreateAssemblyIdentity(AssemblyIdentity baseIdentity, A
public override bool Execute()
{
+ if (!NativeMethodsShared.IsWindows)
+ {
+ Log.LogErrorWithCodeFromResources("General.TaskRequiresWindows", nameof(GenerateManifestBase));
+ return false;
+ }
+
bool success = true;
Type manifestType = GetObjectType();
diff --git a/src/Tasks/ManifestUtil/ComImporter.cs b/src/Tasks/ManifestUtil/ComImporter.cs
index 86e28d204d0..96a941a43e0 100644
--- a/src/Tasks/ManifestUtil/ComImporter.cs
+++ b/src/Tasks/ManifestUtil/ComImporter.cs
@@ -10,11 +10,13 @@
#if RUNTIME_TYPE_NETCORE
using System.Runtime.InteropServices.ComTypes;
#endif
+using System.Runtime.Versioning;
#nullable disable
namespace Microsoft.Build.Tasks.Deployment.ManifestUtilities
{
+ [SupportedOSPlatform("windows")]
internal class ComImporter
{
private readonly OutputMessageCollection _outputMessages;
diff --git a/src/Tasks/ManifestUtil/FileReference.cs b/src/Tasks/ManifestUtil/FileReference.cs
index e2e0f6b75d8..e13dad0af4f 100644
--- a/src/Tasks/ManifestUtil/FileReference.cs
+++ b/src/Tasks/ManifestUtil/FileReference.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
using System.Text;
using System.Xml.Serialization;
@@ -44,6 +45,7 @@ public FileReference(string path) : base(path)
[XmlIgnore]
public ComClass[] ComClasses => _comClasses;
+ [SupportedOSPlatform("windows")]
internal bool ImportComComponent(string path, OutputMessageCollection outputMessages, string outputDisplayName)
{
var importer = new ComImporter(path, outputMessages, outputDisplayName);
@@ -103,7 +105,7 @@ public bool IsDataFile
[XmlIgnore]
public TypeLib[] TypeLibs => _typeLibs;
- #region " XmlSerializer "
+#region " XmlSerializer "
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -141,7 +143,7 @@ public string XmlWriteableType
set => _writeableType = value;
}
- #endregion
+#endregion
}
[ComVisible(false)]
@@ -181,7 +183,7 @@ internal ComClass(Guid tlbId, Guid clsId, string progId, string threadingModel,
[XmlIgnore]
public string TlbId => _tlbid;
- #region " XmlSerializer "
+#region " XmlSerializer "
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -228,7 +230,7 @@ public string XmlTlbId
set => _tlbid = value;
}
- #endregion
+#endregion
}
[ComVisible(false)]
@@ -293,7 +295,7 @@ private static string FlagsFromInt(int flags)
[XmlIgnore]
public string Version => _version;
- #region " XmlSerializer "
+#region " XmlSerializer "
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -340,7 +342,7 @@ public string XmlVersion
set => _version = value;
}
- #endregion
+#endregion
}
[ComVisible(false)]
@@ -380,7 +382,7 @@ public bool Versioned
}
}
- #region " XmlSerializer "
+#region " XmlSerializer "
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -400,7 +402,7 @@ public string XmlVersioned
set => _versioned = value;
}
- #endregion
+#endregion
}
[ComVisible(false)]
@@ -427,7 +429,7 @@ public class ProxyStub
[XmlIgnore]
public string TlbId => _tlbid;
- #region " XmlSerializer "
+#region " XmlSerializer "
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -474,6 +476,6 @@ public string XmlTlbId
set => _tlbid = value;
}
- #endregion
+#endregion
}
}
diff --git a/src/Tasks/ManifestUtil/SecurityUtil.cs b/src/Tasks/ManifestUtil/SecurityUtil.cs
index 54a9221d899..986370caf84 100644
--- a/src/Tasks/ManifestUtil/SecurityUtil.cs
+++ b/src/Tasks/ManifestUtil/SecurityUtil.cs
@@ -1,9 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if !RUNTIME_TYPE_NETCORE
using Microsoft.Build.Framework;
-#endif
using Microsoft.Build.Utilities;
using Microsoft.Win32;
using System;
@@ -22,6 +20,7 @@
using System.Reflection;
#endif
using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
@@ -32,9 +31,6 @@
using System.Text;
using System.Xml;
using Microsoft.Build.Shared.FileSystem;
-#if !RUNTIME_TYPE_NETCORE
-using FrameworkNameVersioning = System.Runtime.Versioning.FrameworkName;
-#endif
#nullable disable
@@ -143,15 +139,15 @@ private static PermissionSet GetNamedPermissionSetFromZone(string targetZone, st
private static PermissionSet GetNamedPermissionSet(string targetZone, string targetFrameworkMoniker)
{
- FrameworkNameVersioning fn;
+ FrameworkName fn;
if (!string.IsNullOrEmpty(targetFrameworkMoniker))
{
- fn = new FrameworkNameVersioning(targetFrameworkMoniker);
+ fn = new FrameworkName(targetFrameworkMoniker);
}
else
{
- fn = new FrameworkNameVersioning(".NETFramework", s_dotNet40Version);
+ fn = new FrameworkName(".NETFramework", s_dotNet40Version);
}
int majorVersion = fn.Version.Major;
@@ -170,7 +166,7 @@ private static PermissionSet GetNamedPermissionSet(string targetZone, string tar
}
}
- private static XmlElement GetXmlElement(string targetZone, FrameworkNameVersioning fn)
+ private static XmlElement GetXmlElement(string targetZone, FrameworkName fn)
{
IList paths = ToolLocationHelper.GetPathToReferenceAssemblies(fn);
@@ -495,6 +491,7 @@ public static PermissionSet XmlToPermissionSet(XmlElement element)
/// Hexadecimal string that contains the SHA-1 hash of the certificate.
/// URL that specifies an address of a time stamping server.
/// Path of the file to sign with the certificate.
+ [SupportedOSPlatform("windows")]
public static void SignFile(string certThumbprint, Uri timestampUrl, string path)
{
SignFile(certThumbprint, timestampUrl, path, null, null);
@@ -507,6 +504,7 @@ public static void SignFile(string certThumbprint, Uri timestampUrl, string path
/// URL that specifies an address of a time stamping server.
/// Path of the file to sign with the certificate.
/// Version of the .NET Framework for the target.
+ [SupportedOSPlatform("windows")]
public static void SignFile(string certThumbprint,
Uri timestampUrl,
string path,
@@ -523,6 +521,7 @@ public static void SignFile(string certThumbprint,
/// Path of the file to sign with the certificate.
/// Version of the .NET Framework for the target.
/// .NET Framework identifier for the target.
+ [SupportedOSPlatform("windows")]
public static void SignFile(string certThumbprint,
Uri timestampUrl,
string path,
@@ -541,6 +540,7 @@ public static void SignFile(string certThumbprint,
/// Version of the .NET Framework for the target.
/// .NET Framework identifier for the target.
/// Disallow fallback to legacy timestamping when RFC3161 timestamping fails during manifest signing
+ [SupportedOSPlatform("windows")]
public static void SignFile(string certThumbprint,
Uri timestampUrl,
string path,
@@ -599,6 +599,7 @@ public static void SignFile(string certThumbprint,
/// URL that specifies an address of a time stamping server.
/// Path of the file to sign with the certificate.
/// This function is only for signing a manifest, not a PE file.
+ [SupportedOSPlatform("windows")]
public static void SignFile(string certPath, SecureString certPassword, Uri timestampUrl, string path)
{
X509Certificate2 cert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.PersistKeySet);
@@ -623,6 +624,7 @@ private static bool UseSha256Algorithm(X509Certificate2 cert)
/// Path of the file to sign with the certificate.
/// This function can only sign a PE file if the X509Certificate2 parameter represents a certificate in the
/// current user's personal certificate store.
+ [SupportedOSPlatform("windows")]
public static void SignFile(X509Certificate2 cert, Uri timestampUrl, string path)
{
// setup resources
@@ -630,6 +632,7 @@ public static void SignFile(X509Certificate2 cert, Uri timestampUrl, string path
SignFileInternal(cert, timestampUrl, path, true, resources);
}
+ [SupportedOSPlatform("windows")]
private static void SignFileInternal(X509Certificate2 cert,
Uri timestampUrl,
string path,
@@ -839,7 +842,7 @@ internal static string GetPathToTool(System.Resources.ResourceManager resources)
toolPath = Path.Combine(pathToDotNetFrameworkSdk, "bin", ToolName);
}
}
- if (toolPath == null || !FileSystems.Default.FileExists(toolPath))
+ if (NativeMethodsShared.IsWindows && (toolPath == null || !FileSystems.Default.FileExists(toolPath)))
{
toolPath = GetVersionIndependentToolPath(ToolName);
}
@@ -893,6 +896,7 @@ private static bool IsCertInStore(X509Certificate2 cert)
return false;
}
+ [SupportedOSPlatform("windows")]
private static string GetVersionIndependentToolPath(string toolName)
{
const string versionIndependentToolKeyName = @"Software\Microsoft\ClickOnce\SignTool";
diff --git a/src/Tasks/ManifestUtil/Util.cs b/src/Tasks/ManifestUtil/Util.cs
index 4f098df2091..56ba265c495 100644
--- a/src/Tasks/ManifestUtil/Util.cs
+++ b/src/Tasks/ManifestUtil/Util.cs
@@ -13,6 +13,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Text;
@@ -226,11 +227,11 @@ private static void GetFileInfoImpl(string path, string targetFrameWorkVersion,
if (string.IsNullOrEmpty(targetFrameWorkVersion) || CompareFrameworkVersions(targetFrameWorkVersion, Constants.TargetFrameworkVersion40) <= 0)
{
- hashAlg = new SHA1CryptoServiceProvider();
+ hashAlg = SHA1.Create("System.Security.Cryptography.SHA1CryptoServiceProvider");
}
else
{
- hashAlg = new SHA256CryptoServiceProvider();
+ hashAlg = SHA256.Create("System.Security.Cryptography.SHA256CryptoServiceProvider");
}
byte[] hashBytes = hashAlg.ComputeHash(s);
hash = Convert.ToBase64String(hashBytes);
@@ -250,6 +251,7 @@ private static string GetLogPath()
return logPath;
}
+ [SupportedOSPlatform("windows")]
public static string GetRegisteredOrganization()
{
RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", false);
@@ -515,7 +517,7 @@ public static string WriteTempFile(string s)
return path;
}
- #region ItemComparer
+#region ItemComparer
private static readonly ItemComparer s_itemComparer = new ItemComparer();
private class ItemComparer : IComparer
{
@@ -541,7 +543,7 @@ int IComparer.Compare(object obj1, object obj2)
return String.Compare(item1.ItemSpec, item2.ItemSpec, StringComparison.Ordinal);
}
}
- #endregion
+#endregion
public static Version ConvertFrameworkVersionToString(string version)
{
diff --git a/src/Tasks/ManifestUtil/mansign2.cs b/src/Tasks/ManifestUtil/mansign2.cs
index d94b4f12a9a..8d0d9fbf267 100644
--- a/src/Tasks/ManifestUtil/mansign2.cs
+++ b/src/Tasks/ManifestUtil/mansign2.cs
@@ -12,6 +12,7 @@
using System.Text;
using System.Xml;
using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
using _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
@@ -273,7 +274,7 @@ private void init()
Sha256SignatureMethodUri);
#if RUNTIME_TYPE_NETCORE
- CryptoConfig.AddAlgorithm(typeof(SHA256Managed),
+ CryptoConfig.AddAlgorithm(typeof(SHA256),
Sha256DigestMethod);
#else
CryptoConfig.AddAlgorithm(typeof(System.Security.Cryptography.SHA256Cng),
@@ -294,6 +295,7 @@ public override XmlElement GetIdElement(XmlDocument document, string idValue)
}
}
+ [SupportedOSPlatform("windows")]
internal class SignedCmiManifest2
{
private XmlDocument _manifestDom = null;
@@ -553,7 +555,7 @@ private static byte[] ComputeHashFromManifest(XmlDocument manifestDom, bool oldF
if (useSha256)
{
- using (SHA256CryptoServiceProvider sha2 = new SHA256CryptoServiceProvider())
+ using (SHA256 sha2 = SHA256.Create("System.Security.Cryptography.SHA256CryptoServiceProvider"))
{
byte[] hash = sha2.ComputeHash(exc.GetOutput() as MemoryStream);
if (hash == null)
@@ -566,7 +568,7 @@ private static byte[] ComputeHashFromManifest(XmlDocument manifestDom, bool oldF
}
else
{
- using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
+ using (SHA1 sha1 = SHA1.Create("System.Security.Cryptography.SHA1CryptoServiceProvider"))
{
byte[] hash = sha1.ComputeHash(exc.GetOutput() as MemoryStream);
if (hash == null)
@@ -601,7 +603,7 @@ private static byte[] ComputeHashFromManifest(XmlDocument manifestDom, bool oldF
if (useSha256)
{
- using (SHA256CryptoServiceProvider sha2 = new SHA256CryptoServiceProvider())
+ using (SHA256 sha2 = SHA256.Create("System.Security.Cryptography.SHA256CryptoServiceProvider"))
{
byte[] hash = sha2.ComputeHash(exc.GetOutput() as MemoryStream);
if (hash == null)
@@ -614,7 +616,7 @@ private static byte[] ComputeHashFromManifest(XmlDocument manifestDom, bool oldF
}
else
{
- using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
+ using (SHA1 sha1 = SHA1.Create("System.Security.Cryptography.SHA1CryptoServiceProvider"))
{
byte[] hash = sha1.ComputeHash(exc.GetOutput() as MemoryStream);
if (hash == null)
@@ -1206,6 +1208,7 @@ internal AsymmetricAlgorithm PublicKey
}
}
+ [SupportedOSPlatform("windows")]
internal class CmiAuthenticodeSignerInfo
{
private int _error = 0;
@@ -1332,6 +1335,7 @@ internal X509Chain SignerChain
}
}
+ [SupportedOSPlatform("windows")]
internal class CmiAuthenticodeTimestamperInfo
{
private int _error = 0;
diff --git a/src/Tasks/Microsoft.Build.Tasks.csproj b/src/Tasks/Microsoft.Build.Tasks.csproj
index 2db4195b003..6a3ccbfc7e4 100644
--- a/src/Tasks/Microsoft.Build.Tasks.csproj
+++ b/src/Tasks/Microsoft.Build.Tasks.csproj
@@ -957,8 +957,10 @@
-
-
+
+
+
+
@@ -968,6 +970,15 @@
+
+
+
+
+
+
+
diff --git a/src/Tasks/NativeMethods.cs b/src/Tasks/NativeMethods.cs
index 45bc7d9faad..94ec0181eb5 100644
--- a/src/Tasks/NativeMethods.cs
+++ b/src/Tasks/NativeMethods.cs
@@ -3,9 +3,12 @@
using System;
using System.IO;
+using System.Runtime.InteropServices;
+using Microsoft.Build.Shared.FileSystem;
+
+#if FEATURE_COM_INTEROP
using System.Text;
using System.Reflection;
-using System.Runtime.InteropServices;
using Microsoft.Build.Shared;
using System.Collections.Generic;
using System.Collections;
@@ -13,7 +16,7 @@
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Text.RegularExpressions;
-using Microsoft.Build.Shared.FileSystem;
+#endif
#nullable disable
@@ -522,7 +525,7 @@ internal enum SymbolicLink
///
internal static class NativeMethods
{
- #region Constants
+#region Constants
internal static readonly IntPtr NullPtr = IntPtr.Zero;
internal static readonly IntPtr InvalidIntPtr = new IntPtr(-1);
@@ -627,9 +630,9 @@ internal enum MoveFileFlags
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
}
- #endregion
+#endregion
- #region NT header stuff
+#region NT header stuff
internal const uint IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
internal const uint IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
@@ -780,9 +783,9 @@ internal struct CRYPTOAPI_BLOB
internal IntPtr pbData;
}
- #endregion
+#endregion
- #region PInvoke
+#region PInvoke
private const string Crypt32DLL = "crypt32.dll";
private const string Advapi32DLL = "advapi32.dll";
#if !RUNTIME_TYPE_NETCORE
diff --git a/src/Tasks/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Tasks/PublicAPI/net/PublicAPI.Unshipped.txt
index 78e394ce7bc..5f9ec5dc2a5 100644
--- a/src/Tasks/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Tasks/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -1,3 +1,5 @@
Microsoft.Build.Tasks.SignFile.DisallowMansignTimestampFallback.get -> bool
Microsoft.Build.Tasks.SignFile.DisallowMansignTimestampFallback.set -> void
+override Microsoft.Build.Tasks.GenerateApplicationManifest.Execute() -> bool
+override Microsoft.Build.Tasks.GenerateDeploymentManifest.Execute() -> bool
static Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile(string certThumbprint, System.Uri timestampUrl, string path, string targetFrameworkVersion, string targetFrameworkIdentifier, bool disallowMansignTimestampFallback) -> void
diff --git a/src/Tasks/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Tasks/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 78e394ce7bc..5f9ec5dc2a5 100644
--- a/src/Tasks/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Tasks/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -1,3 +1,5 @@
Microsoft.Build.Tasks.SignFile.DisallowMansignTimestampFallback.get -> bool
Microsoft.Build.Tasks.SignFile.DisallowMansignTimestampFallback.set -> void
+override Microsoft.Build.Tasks.GenerateApplicationManifest.Execute() -> bool
+override Microsoft.Build.Tasks.GenerateDeploymentManifest.Execute() -> bool
static Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile(string certThumbprint, System.Uri timestampUrl, string path, string targetFrameworkVersion, string targetFrameworkIdentifier, bool disallowMansignTimestampFallback) -> void
diff --git a/src/Tasks/Resources/Strings.resx b/src/Tasks/Resources/Strings.resx
index 07b5097294d..d0dd9311e15 100644
--- a/src/Tasks/Resources/Strings.resx
+++ b/src/Tasks/Resources/Strings.resx
@@ -571,6 +571,10 @@
MSB3094: "{2}" refers to {0} item(s), and "{3}" refers to {1} item(s). They must have the same number of items.
{StrBegin="MSB3094: "}
+
+ MSB3096: Task "{0}" is only supported when building on Windows.
+ {StrBegin="MSB3096: "}
+