diff --git a/.vscode/launch.json b/.vscode/launch.json index df92e58e454b2..e05a5afd5d334 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -62,6 +62,51 @@ "stopAtEntry": false, "console": "internalConsole" }, + { + "name": "Launch Microsoft.Build.Tasks.CodeAnalysis.dll via MSBuild.exe (netfx)", + "type": "clr", + "request": "launch", + "preLaunchTask": "build toolset", + "program": "C:/Program Files/Microsoft Visual Studio/2022/Preview/MSBuild/Current/Bin/amd64/MSBuild.exe", + "args": [ + "-restore", + "-p:RoslynTargetsPath=${workspaceFolder}/artifacts/bin/Microsoft.Net.Compilers.Toolset.Package/Debug/tasks/net472", + ], + // A simple project that can be used to debug the build tasks against. + "cwd": "${workspaceFolder}/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator", + "stopAtEntry": false, + "console": "internalConsole" + }, + { + "name": "Launch Microsoft.Build.Tasks.CodeAnalysis.dll via MSBuild.exe (netcore)", + "type": "clr", + "request": "launch", + "preLaunchTask": "build toolset", + "program": "C:/Program Files/Microsoft Visual Studio/2022/Preview/MSBuild/Current/Bin/amd64/MSBuild.exe", + "args": [ + "-restore", + "-p:RoslynTargetsPath=${workspaceFolder}/artifacts/bin/Microsoft.Net.Compilers.Toolset.Package/Debug/tasks/netcore", + ], + // A simple project that can be used to debug the build tasks against. + "cwd": "${workspaceFolder}/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator", + "stopAtEntry": false, + "console": "internalConsole" + }, + { + "name": "Launch Microsoft.Build.Tasks.CodeAnalysis.dll via dotnet build", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build toolset", + "program": "dotnet", + "args": [ + "build", + "-p:RoslynTargetsPath=${workspaceFolder}/artifacts/bin/Microsoft.Net.Compilers.Toolset.Package/Debug/tasks/netcore", + ], + // A simple project that can be used to debug the build tasks against. + "cwd": "${workspaceFolder}/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator", + "stopAtEntry": false, + "console": "internalConsole" + }, { "name": ".NET Core Launch (console)", "type": "coreclr", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5ac5060625cf5..ea68cf0efae7d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -97,6 +97,18 @@ "problemMatcher": "$msCompile", "group": "build" }, + { + "label": "build toolset", + "type": "shell", + "command": "dotnet", + "args": [ + "build", + "-p:GenerateFullPaths=true", + "${workspaceFolder}/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/Microsoft.Net.Compilers.Toolset.Package.csproj" + ], + "problemMatcher": "$msCompile", + "group": "build" + }, { "label": "msbuild current project", "type": "shell", diff --git a/src/Compilers/Core/CommandLine/NativeMethods.cs b/src/Compilers/Core/CommandLine/NativeMethods.cs index 18c930318da1d..c5008b95be2dc 100644 --- a/src/Compilers/Core/CommandLine/NativeMethods.cs +++ b/src/Compilers/Core/CommandLine/NativeMethods.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text; namespace Microsoft.CodeAnalysis.CommandLine @@ -43,6 +44,9 @@ internal struct PROCESS_INFORMATION /// /// Interop methods. /// +#if NET + [SupportedOSPlatform("windows")] +#endif internal static class NativeMethods { #region Constants diff --git a/src/Compilers/Core/MSBuildTask/InteractiveCompiler.cs b/src/Compilers/Core/MSBuildTask/InteractiveCompiler.cs index 6b82385f2725e..c26a3cb0f2d44 100644 --- a/src/Compilers/Core/MSBuildTask/InteractiveCompiler.cs +++ b/src/Compilers/Core/MSBuildTask/InteractiveCompiler.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.BuildTasks { /// - /// This class defines all of the common stuff that is shared between the Vbc and Csc tasks. + /// This class defines all of the common stuff that is shared between the Vbi and Csi tasks. /// This class is not instantiatable as a Task just by itself. /// public abstract class InteractiveCompiler : ManagedToolTask diff --git a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs index 6c063f3cb2585..25f293ed2ad33 100644 --- a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs +++ b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs @@ -487,6 +487,27 @@ public bool ReportIVTs get { return _store.GetOrDefault(nameof(ReportIVTs), false); } } + public string? CompilerType + { + set { _store[nameof(CompilerType)] = value; } + get { return (string?)_store[nameof(CompilerType)]; } + } + + protected override RoslynCompilerType GetCompilerType() + { + if (string.IsNullOrWhiteSpace(CompilerType)) + { + return DefaultCompilerType; + } + + if (Enum.TryParse(CompilerType, ignoreCase: true, out var compilerType)) + { + return compilerType; + } + + throw new ArgumentException($"Invalid {nameof(CompilerType)} '{CompilerType}' specified. Valid values are {string.Join(", ", Enum.GetNames(typeof(RoslynCompilerType)))}."); + } + #endregion /// @@ -1226,4 +1247,11 @@ internal string? GetWin32ManifestSwitch return win32Manifest; } } + + public enum RoslynCompilerType + { + Core, + Framework, + FrameworkPackage, + } } diff --git a/src/Compilers/Core/MSBuildTask/ManagedToolTask.cs b/src/Compilers/Core/MSBuildTask/ManagedToolTask.cs index c12dfc3eb08cf..11f9802a8021b 100644 --- a/src/Compilers/Core/MSBuildTask/ManagedToolTask.cs +++ b/src/Compilers/Core/MSBuildTask/ManagedToolTask.cs @@ -28,7 +28,20 @@ public abstract class ManagedToolTask : ToolTask /// protected bool IsManagedTool => string.IsNullOrEmpty(ToolPath) && ToolExe == ToolName; - internal string PathToManagedTool => Utilities.GenerateFullPathToTool(ToolName); + /// + /// Used to determine the directory where the tools (like csc) are located. + /// See . + /// + protected virtual RoslynCompilerType GetCompilerType() => DefaultCompilerType; + + protected const RoslynCompilerType DefaultCompilerType +#if NET + = RoslynCompilerType.Core; +#else + = RoslynCompilerType.Framework; +#endif + + internal string PathToManagedTool => Utilities.GenerateFullPathToTool(ToolName, GetCompilerType()); private string PathToManagedToolWithoutExtension { diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets index e595f62d2c33a..47ec26271d96c 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets @@ -94,6 +94,7 @@ ChecksumAlgorithm="$(ChecksumAlgorithm)" CodeAnalysisRuleSet="$(ResolvedCodeAnalysisRuleSet)" CodePage="$(CodePage)" + CompilerType="$(RoslynCompilerType)" DebugType="$(DebugType)" DefineConstants="$(DefineConstants)" DelaySign="$(DelaySign)" diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets index 10e9995ace985..b40b3f0746821 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets @@ -1,10 +1,15 @@  + + <_BuildTasksDirectory>$(MSBuildThisFileDirectory) + <_BuildTasksDirectory Condition="Exists('$(RoslynTargetsPath)')">$(RoslynTargetsPath)\ + + - + @@ -58,7 +63,7 @@ ======================== --> - + @@ -151,7 +156,7 @@ --> - + [!NOTE] In VSCode, you can use one of the `Microsoft.Build.Tasks.CodeAnalysis.dll` launch targets. + Debugging this code requires a bit of setup because it's not an independent component. It relies on having other parts of the toolset deployed in the same directory. Additionally the project being debugged needs to be modified to ensure this DLL is built instead of the one that ships along side MSBuild. Set the startup project to Toolset. This project properly deploys all of the necessary components and hence provides a simple F5 experience. @@ -26,9 +28,3 @@ The target project itself needs to be modified so that it will load the freshly Replace `e:\dd\roslyn` with the path to your Roslyn enlistment. Once that is all done you should be able to F5 the Toolset project and debug the MSBuild task directly. - - - - - - diff --git a/src/Compilers/Core/MSBuildTask/Utilities.cs b/src/Compilers/Core/MSBuildTask/Utilities.cs index 4dc156b01f2aa..70a3ade4fe56a 100644 --- a/src/Compilers/Core/MSBuildTask/Utilities.cs +++ b/src/Compilers/Core/MSBuildTask/Utilities.cs @@ -171,14 +171,14 @@ internal static Exception GetLocalizedArgumentException(string errorString, /// /// Generate the full path to the tool that is deployed with our build tasks. /// - internal static string GenerateFullPathToTool(string toolFileName) + internal static string GenerateFullPathToTool(string toolFileName, RoslynCompilerType compilerType) { var buildTask = typeof(Utilities).GetTypeInfo().Assembly; var assemblyPath = buildTask.Location; var assemblyDirectory = Path.GetDirectoryName(assemblyPath)!; return RuntimeHostInfo.IsDesktopRuntime - ? Path.Combine(assemblyDirectory, toolFileName) + ? Path.Combine(assemblyDirectory, compilerType is RoslynCompilerType.Core ? "../bincore" : "", toolFileName) : Path.Combine(assemblyDirectory, "bincore", toolFileName); } } diff --git a/src/Compilers/Core/MSBuildTaskTests/MiscTests.cs b/src/Compilers/Core/MSBuildTaskTests/MiscTests.cs index 96034040c66f0..12c36225a5f92 100644 --- a/src/Compilers/Core/MSBuildTaskTests/MiscTests.cs +++ b/src/Compilers/Core/MSBuildTaskTests/MiscTests.cs @@ -2,15 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Linq; -using Microsoft.Build.Framework; -using Microsoft.CodeAnalysis.BuildTasks; -using Xunit; -using Moq; -using Roslyn.Test.Utilities; -using Microsoft.CodeAnalysis.CSharp; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CSharp; +using Roslyn.Test.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.BuildTasks.UnitTests { diff --git a/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs b/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs index 4cd66c6e5b5ee..8058de5dce4c2 100644 --- a/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs +++ b/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs @@ -130,9 +130,10 @@ public async Task IncorrectServerHashReturnsIncorrectHashResponse() public void QuotePipeName_Desktop() { var serverInfo = BuildServerConnection.GetServerProcessInfo(@"q:\tools", "name with space"); - Assert.Equal(@"q:\tools\VBCSCompiler.exe", serverInfo.processFilePath); - Assert.Equal(@"q:\tools\VBCSCompiler.exe", serverInfo.toolFilePath); - Assert.Equal(@"""-pipename:name with space""", serverInfo.commandLineArguments); + // Because q:\tools\VBCSCompiler.exe does not exist, the fallback 'dotnet exec VBCSCompiler.dll' is returned. + Assert.EndsWith(@"\dotnet.exe", serverInfo.processFilePath); + Assert.Equal(@"q:\tools\VBCSCompiler.dll", serverInfo.toolFilePath); + Assert.Equal(@"exec ""q:\tools\VBCSCompiler.dll"" ""-pipename:name with space""", serverInfo.commandLineArguments); } [ConditionalFact(typeof(CoreClrOnly))] diff --git a/src/Compilers/Shared/BuildClient.cs b/src/Compilers/Shared/BuildClient.cs index 88fec0d5687c8..a7901dc62c62d 100644 --- a/src/Compilers/Shared/BuildClient.cs +++ b/src/Compilers/Shared/BuildClient.cs @@ -351,6 +351,8 @@ private static bool AreNamedPipesSupported() /// private static IEnumerable GetCommandLineWindows(IEnumerable args) { + Debug.Assert(PlatformInformation.IsWindows); + IntPtr ptr = NativeMethods.GetCommandLine(); if (ptr == IntPtr.Zero) { diff --git a/src/Compilers/Shared/BuildServerConnection.cs b/src/Compilers/Shared/BuildServerConnection.cs index c8596ba8b7dc1..81beffe39083c 100644 --- a/src/Compilers/Shared/BuildServerConnection.cs +++ b/src/Compilers/Shared/BuildServerConnection.cs @@ -543,11 +543,9 @@ internal static string GetPipeName(string clientDirectory) bool isAdmin = false; if (PlatformInformation.IsWindows) { -#pragma warning disable CA1416 // Validate platform compatibility var currentIdentity = WindowsIdentity.GetCurrent(); var principal = new WindowsPrincipal(currentIdentity); isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator); -#pragma warning restore CA1416 } var userName = Environment.UserName; diff --git a/src/Compilers/Shared/NamedPipeUtil.cs b/src/Compilers/Shared/NamedPipeUtil.cs index 6e313e8e32be0..0a45e71b27ba1 100644 --- a/src/Compilers/Shared/NamedPipeUtil.cs +++ b/src/Compilers/Shared/NamedPipeUtil.cs @@ -55,7 +55,6 @@ internal static bool CheckClientElevationMatches(NamedPipeServerStream pipeStrea { if (PlatformInformation.IsWindows) { -#pragma warning disable CA1416 // Validate platform compatibility var serverIdentity = getIdentity(); (string name, bool admin) clientIdentity = default; @@ -72,7 +71,6 @@ internal static bool CheckClientElevationMatches(NamedPipeServerStream pipeStrea var elevatedToAdmin = currentPrincipal.IsInRole(WindowsBuiltInRole.Administrator); return (currentIdentity.Name, elevatedToAdmin); } -#pragma warning restore CA1416 // Validate platform compatibility } return true; diff --git a/src/Compilers/Shared/RuntimeHostInfo.cs b/src/Compilers/Shared/RuntimeHostInfo.cs index 28c6a9644181b..eae44029ff34c 100644 --- a/src/Compilers/Shared/RuntimeHostInfo.cs +++ b/src/Compilers/Shared/RuntimeHostInfo.cs @@ -25,7 +25,6 @@ internal static class RuntimeHostInfo /// internal static (string processFilePath, string commandLineArguments, string toolFilePath) GetProcessInfo(string toolFilePathWithoutExtension, string commandLineArguments) { -#if NET // First check for an app host file and return that if it's available. var appHostSuffix = PlatformInformation.IsWindows ? ".exe" : ""; var appFilePath = $"{toolFilePathWithoutExtension}{appHostSuffix}"; @@ -39,17 +38,17 @@ internal static (string processFilePath, string commandLineArguments, string too var dotnetFilePath = GetDotNetPathOrDefault(); commandLineArguments = $@"exec ""{toolFilePath}"" {commandLineArguments}"; return (dotnetFilePath, commandLineArguments, toolFilePath); -#else - var toolFilePath = $"{toolFilePathWithoutExtension}.exe"; - return (toolFilePath, commandLineArguments, toolFilePath); -#endif } + internal static bool IsCoreClrRuntime => #if NET - - internal static bool IsCoreClrRuntime => true; + true; +#else + false; +#endif private const string DotNetHostPathEnvironmentName = "DOTNET_HOST_PATH"; + private const string DotNetExperimentalHostPathEnvironmentName = "DOTNET_EXPERIMENTAL_HOST_PATH"; /// /// Get the path to the dotnet executable. In the case the .NET SDK did not provide this information @@ -58,14 +57,19 @@ internal static (string processFilePath, string commandLineArguments, string too /// internal static string GetDotNetPathOrDefault() { - if (Environment.GetEnvironmentVariable(DotNetHostPathEnvironmentName) is string pathToDotNet) + if (Environment.GetEnvironmentVariable(DotNetHostPathEnvironmentName) is { Length: > 0 } pathToDotNet) { return pathToDotNet; } + if (Environment.GetEnvironmentVariable(DotNetExperimentalHostPathEnvironmentName) is { Length: > 0 } pathToDotNetExperimental) + { + return pathToDotNetExperimental; + } + var (fileName, sep) = PlatformInformation.IsWindows - ? ("dotnet.exe", ';') - : ("dotnet", ':'); + ? ("dotnet.exe", new char[] { ';' }) + : ("dotnet", new char[] { ':' }); var path = Environment.GetEnvironmentVariable("PATH") ?? ""; foreach (var item in path.Split(sep, StringSplitOptions.RemoveEmptyEntries)) @@ -86,11 +90,5 @@ internal static string GetDotNetPathOrDefault() return fileName; } - -#else - - internal static bool IsCoreClrRuntime => false; - -#endif } } diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/Microsoft.Net.Compilers.Toolset.Package.csproj b/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/Microsoft.Net.Compilers.Toolset.Package.csproj index aa4c185f4f0fc..1fffc914ab7a4 100644 --- a/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/Microsoft.Net.Compilers.Toolset.Package.csproj +++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/Microsoft.Net.Compilers.Toolset.Package.csproj @@ -19,7 +19,6 @@ $(RoslynPackageDescriptionDetails) - $(TargetsForTfmSpecificContentInPackage);_GetFilesToPackage $(NoWarn);NU5100;NU5128 @@ -47,17 +46,25 @@ - + <_File Include="@(DesktopCompilerArtifact)" TargetDir="tasks/net472"/> <_File Include="@(DesktopCompilerResourceArtifact)" TargetDir="tasks/net472"/> - <_File Include="@(CoreClrCompilerBuildArtifact)" TargetDir="tasks/netcore"/> <_File Include="@(CoreClrCompilerToolsArtifact)" TargetDir="tasks/netcore"/> <_File Include="@(CoreClrCompilerBinArtifact)" TargetDir="tasks/netcore/bincore"/> <_File Include="@(CoreClrCompilerBinRuntimesArtifact)" TargetDir="tasks/netcore/bincore/runtimes"/> - - + <_File Include="@(DesktopCompilerArtifact)" Condition="'%(DesktopCompilerArtifact.NeededForBuildTask)' == 'true'" TargetDir="tasks/netcore/binfx"/> + <_File Include="@(DesktopCompilerResourceArtifact)" Condition="'%(DesktopCompilerResourceArtifact.NeededForBuildTask)' == 'true'" TargetDir="tasks/netcore/binfx"/> + + <_FileWithPath Include="@(_File)" TargetPath="%(_File.TargetDir)/%(_File.RecursiveDir)%(_File.FileName)%(_File.Extension)" /> + + + + + diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets b/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets index 3a2eb7c1ea3fa..5e5207a85e1bb 100644 --- a/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets +++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets @@ -48,7 +48,7 @@ - + @@ -62,19 +62,19 @@ We don't currently collect optimization data for the following assemblies. --> - <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Buffers.dll"/> + <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Buffers.dll" NeededForBuildTask="true"/> <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Collections.Immutable.dll"/> - <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Memory.dll"/> - <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Numerics.Vectors.dll"/> + <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Memory.dll" NeededForBuildTask="true"/> + <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Numerics.Vectors.dll"/> <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Reflection.Metadata.dll"/> - <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Runtime.CompilerServices.Unsafe.dll"/> - <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Text.Encoding.CodePages.dll"/> - <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Threading.Tasks.Extensions.dll"/> + <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Runtime.CompilerServices.Unsafe.dll" NeededForBuildTask="true"/> + <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Text.Encoding.CodePages.dll"/> + <_NoOptimizationData Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Threading.Tasks.Extensions.dll"/> - <_NoNGen Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Numerics.Vectors.dll"/> + <_NoNGen Include="$(ArtifactsBinDir)csi\$(Configuration)\net472\System.Numerics.Vectors.dll" NeededForBuildTask="true"/> @@ -86,7 +86,7 @@ - + diff --git a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs index 684318a2ba787..4720b750bfc93 100644 --- a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs +++ b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs @@ -180,7 +180,8 @@ private bool CheckPackages(TextWriter textWriter) FindNuGetPackage(Path.Combine(ArtifactsDirectory, "packages", Configuration, "Shipping"), "Microsoft.Net.Compilers.Toolset"), excludeFunc: relativeFileName => relativeFileName.StartsWith(@"tasks\netcore\bincore\Microsoft.DiaSymReader.Native", PathComparison) || - relativeFileName.StartsWith(@"tasks\netcore\bincore\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.dll", PathComparison), + relativeFileName.StartsWith(@"tasks\netcore\bincore\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.dll", PathComparison) || + (relativeFileName.StartsWith(@"tasks\netcore\binfx\", PathComparison) && relativeFileName.EndsWith(".targets", PathComparison)), (@"tasks\net472", GetProjectOutputDirectory("csc", "net472")), (@"tasks\net472", GetProjectOutputDirectory("vbc", "net472")), (@"tasks\net472", GetProjectOutputDirectory("csi", "net472")), @@ -189,7 +190,8 @@ private bool CheckPackages(TextWriter textWriter) (@"tasks\netcore\bincore", GetProjectPublishDirectory("csc", "net9.0")), (@"tasks\netcore\bincore", GetProjectPublishDirectory("vbc", "net9.0")), (@"tasks\netcore\bincore", GetProjectPublishDirectory("VBCSCompiler", "net9.0")), - (@"tasks\netcore", GetProjectPublishDirectory("Microsoft.Build.Tasks.CodeAnalysis", "net9.0"))); + (@"tasks\netcore", GetProjectPublishDirectory("Microsoft.Build.Tasks.CodeAnalysis", "net9.0")), + (@"tasks\netcore\binfx", GetProjectOutputDirectory("Microsoft.Build.Tasks.CodeAnalysis", "net472"))); foreach (var arch in new[] { "x86", "x64", "arm64" }) {