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: "} +