diff --git a/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs b/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs index 8e9074e1b377..7b3055d90d06 100644 --- a/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs +++ b/test/Microsoft.NET.Build.Tests/RoslynBuildTaskTests.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.Versioning; using Basic.CompilerLog.Util; using Microsoft.Build.Logging.StructuredLogger; using Microsoft.CodeAnalysis; @@ -12,6 +13,9 @@ namespace Microsoft.NET.Build.Tests; public sealed class RoslynBuildTaskTests(ITestOutputHelper log) : SdkTest(log) { + private const string CoreTargetFrameworkName = ".NETCoreApp"; + private const string FxTargetFrameworkName = ".NETFramework"; + private static string CompilerFileNameWithoutExtension(Language language) => language switch { Language.CSharp => "csc", @@ -28,7 +32,7 @@ public void FullMSBuild_SdkStyle(bool useSharedCompilation, Language language) { var testAsset = CreateProject(useSharedCompilation, language); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), CoreTargetFrameworkName, useSharedCompilation); } [FullMSBuildOnlyTheory, CombinatorialData] @@ -39,7 +43,7 @@ public void FullMSBuild_SdkStyle_OptOut(bool useSharedCompilation, Language lang doc.Root!.Element("PropertyGroup")!.Add(new XElement("RoslynCompilerType", "Framework")); }); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), FxTargetFrameworkName, useSharedCompilation); } [FullMSBuildOnlyTheory, CombinatorialData] @@ -51,15 +55,19 @@ public void FullMSBuild_NonSdkStyle(bool useSharedCompilation, Language language project.TargetFrameworkVersion = "v4.7.2"; }); var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), FxTargetFrameworkName, useSharedCompilation); } [FullMSBuildOnlyTheory, CombinatorialData] - public void FullMSBuild_SdkStyle_ToolsetPackage(bool useSharedCompilation, Language language) + public void FullMSBuild_SdkStyle_ToolsetPackage(bool useSharedCompilation, Language language, bool useFrameworkCompiler) { var testAsset = CreateProject(useSharedCompilation, language, AddCompilersToolsetPackage); - var buildCommand = BuildAndRunUsingMSBuild(testAsset); - VerifyCompiler(buildCommand, DotNetExecCompilerFileName(language), useSharedCompilation, toolsetPackage: true); + ReadOnlySpan args = useFrameworkCompiler ? ["-p:RoslynCompilerType=Framework"] : []; + var buildCommand = BuildAndRunUsingMSBuild(testAsset, args); + VerifyCompiler(buildCommand, + useFrameworkCompiler ? AppHostCompilerFileName(language) : DotNetExecCompilerFileName(language), + useFrameworkCompiler ? FxTargetFrameworkName : CoreTargetFrameworkName, + useSharedCompilation, toolsetPackage: true); } [Theory, CombinatorialData] @@ -67,7 +75,7 @@ public void DotNet(bool useSharedCompilation, Language language) { var testAsset = CreateProject(useSharedCompilation, language); var buildCommand = BuildAndRunUsingDotNet(testAsset); - VerifyCompiler(buildCommand, AppHostCompilerFileName(language), useSharedCompilation); + VerifyCompiler(buildCommand, AppHostCompilerFileName(language), CoreTargetFrameworkName, useSharedCompilation); } // https://github.com/dotnet/sdk/issues/49665 @@ -76,7 +84,7 @@ public void DotNet_ToolsetPackage(bool useSharedCompilation, Language language) { var testAsset = CreateProject(useSharedCompilation, language, AddCompilersToolsetPackage); var buildCommand = BuildAndRunUsingDotNet(testAsset); - VerifyCompiler(buildCommand, DotNetExecCompilerFileName(language), useSharedCompilation, toolsetPackage: true); + VerifyCompiler(buildCommand, DotNetExecCompilerFileName(language), CoreTargetFrameworkName, useSharedCompilation, toolsetPackage: true); } private TestAsset CreateProject(bool useSharedCompilation, Language language, Action? configure = null, [CallerMemberName] string callingMethod = "") @@ -130,21 +138,21 @@ private static void AddCompilersToolsetPackage(TestProject project) project.PackageReferences.Add(new TestPackageReference("Microsoft.Net.Compilers.Toolset", roslynVersion)); } - private TestCommand BuildAndRunUsingMSBuild(TestAsset testAsset) + private TestCommand BuildAndRunUsingMSBuild(TestAsset testAsset, params ReadOnlySpan args) { var buildCommand = new MSBuildCommand(testAsset, "Build"); buildCommand.WithWorkingDirectory(testAsset.Path) - .Execute("-bl").Should().Pass(); + .Execute(["-bl", .. args]).Should().Pass(); Run(buildCommand.GetOutputDirectory().File(testAsset.TestProject!.GetOutputFileName())); return buildCommand; } - private TestCommand BuildAndRunUsingDotNet(TestAsset testAsset) + private TestCommand BuildAndRunUsingDotNet(TestAsset testAsset, params ReadOnlySpan args) { var buildCommand = new DotnetBuildCommand(testAsset); - buildCommand.Execute("-bl").Should().Pass(); + buildCommand.Execute(["-bl", .. args]).Should().Pass(); Run(buildCommand.GetOutputDirectory().File(testAsset.TestProject!.GetOutputFileName())); @@ -158,7 +166,7 @@ private void Run(FileInfo outputFile) .And.HaveStdOut("42"); } - private static void VerifyCompiler(TestCommand buildCommand, string compilerFileName, bool usedCompilerServer, bool toolsetPackage = false) + private static void VerifyCompiler(TestCommand buildCommand, string compilerFileName, string targetFrameworkName, bool usedCompilerServer, bool toolsetPackage = false) { var binaryLogPath = Path.Join(buildCommand.WorkingDirectory, "msbuild.binlog"); using (var reader = BinaryLogReader.Create(binaryLogPath)) @@ -175,16 +183,47 @@ private static void VerifyCompiler(TestCommand buildCommand, string compilerFile { call.CompilerFilePath.Should().NotContain(toolsetPackageName); } + + GetTargetFramework(call.CompilerFilePath).Should().StartWith($"{targetFrameworkName},"); } // Verify compiler server message. - var compilerServerMesssages = BinaryLog.ReadBuild(binaryLogPath).FindChildrenRecursive( + var compilerServerMessages = BinaryLog.ReadBuild(binaryLogPath).FindChildrenRecursive( static message => message.Text.StartsWith("CompilerServer:", StringComparison.Ordinal)); - compilerServerMesssages.Should().ContainSingle().Which.Text.Should().StartWith(usedCompilerServer + compilerServerMessages.Should().ContainSingle().Which.Text.Should().StartWith(usedCompilerServer ? "CompilerServer: server - server processed compilation - " : "CompilerServer: tool - using command line tool by design"); } + private static string? GetTargetFramework(string dllPath) + { + // If `dllPath` is an apphost (unmanaged exe), we need to inspect the corresponding dll instead. + var ext = Path.GetExtension(dllPath); + if (ext == FileNameSuffixes.CurrentPlatform.Exe) + { + var fixedDllPath = Path.ChangeExtension(dllPath, ".dll"); + // If a `.dll` does not exist, the `.exe` is a netfx managed assembly and we can use it. + if (File.Exists(fixedDllPath)) + { + dllPath = fixedDllPath; + } + } + else + { + Assert.Equal(".dll", ext); + } + + var tpa = ((string?)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES"))?.Split(Path.PathSeparator) ?? []; + var resolver = new PathAssemblyResolver([.. tpa, dllPath]); + using var mlc = new MetadataLoadContext(resolver); + var asm = mlc.LoadFromAssemblyPath(dllPath); + var attrFullName = typeof(TargetFrameworkAttribute).FullName; + return asm.GetCustomAttributesData() + .Where(a => a.AttributeType.FullName == attrFullName) + .Select(a => a.ConstructorArguments[0].Value) + .FirstOrDefault() as string; + } + public enum Language { CSharp,