From f9cb8aff8cdf9f7cd384c8a44817c8ace05bcea3 Mon Sep 17 00:00:00 2001 From: smolchanovsky Date: Fri, 10 Apr 2026 14:25:45 +0400 Subject: [PATCH] Pass Platform to dotnet build/publish commands (#13) --- .../JitCodegenProviderTests.cs | 59 ++++++++++++++++++- .../JitDisasm/JitCodegenProvider.cs | 14 ++++- .../JitDisasm/JitDisasmProjectContext.cs | 3 +- .../JitDisasmProjectContextFactory.cs | 6 +- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/dotnet/ReSharperPlugin.DotNetDisassembler.Tests/JitCodegenProviderTests.cs b/src/dotnet/ReSharperPlugin.DotNetDisassembler.Tests/JitCodegenProviderTests.cs index 510bbe1..35657ad 100644 --- a/src/dotnet/ReSharperPlugin.DotNetDisassembler.Tests/JitCodegenProviderTests.cs +++ b/src/dotnet/ReSharperPlugin.DotNetDisassembler.Tests/JitCodegenProviderTests.cs @@ -286,6 +286,60 @@ public async Task GetJitCodegen_WithProperty_ShouldReturnAssemblyCode() "Output should contain method or class name"); } + // https://github.com/JetBrains/dotnet-disassembler-plugin/issues/13 + // dotnet build ignores MSBuild properties in platform-conditional PropertyGroups + [Test] + public async Task GetJitCodegen_WithPlatformConditionalProperties_ShouldBuildSuccessfully() + { + // Arrange + var arch = RuntimePlatformUtils.GetCurrentArch(); + + File.WriteAllText(_testProjectFile, $@" + + + Exe + net9.0 + false + Release;Debug + {arch} + + + true + + + true + + "); + + var programFile = Path.Combine(_testProjectDir, "Program.cs"); + File.WriteAllText(programFile, @" + using System; + + public class TestClass + { + public static void Main() + { + Console.WriteLine(Add(2, 3)); + } + + public static unsafe int Add(int a, int b) + { + int result = a + b; + int* p = &result; + return *p; + } + }"); + + var projectContext = CreateProjectContext(platform: arch); + var config = new JitDisasmConfiguration(); + + // Act + var result = await _jitCodegenProvider.GetJitCodegenAsync(_addMethodTarget, projectContext, config, CancellationToken.None); + + // Assert + Assert.True(result.Succeed, $"Error: {result.FailValue?.Code}\nDetails: {result.FailValue?.Details}"); + } + [Test] public async Task GetJitCodegen_WithMissingMethod_ShouldReturnEmptyOrMinimalOutput() { @@ -305,7 +359,7 @@ public async Task GetJitCodegen_WithMissingMethod_ShouldReturnEmptyOrMinimalOutp "Expected empty or minimal output for missing method"); } - private JitDisasmProjectContext CreateProjectContext([CanBeNull] JitDisasmTargetFramework tfm = null) + private JitDisasmProjectContext CreateProjectContext([CanBeNull] JitDisasmTargetFramework tfm = null, [CanBeNull] string platform = null) { var projectRoot = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "..", "..")); var dotnetCmd = Path.Combine(projectRoot, "dotnet.cmd"); @@ -325,6 +379,7 @@ private JitDisasmProjectContext CreateProjectContext([CanBeNull] JitDisasmTarget ProjectFilePath: _testProjectFile, ProjectDirectory: _testProjectDir, AssemblyName: "TestProject", - DotNetCliExePath: dotnetExe); + DotNetCliExePath: dotnetExe, + Platform: platform); } } diff --git a/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitCodegenProvider.cs b/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitCodegenProvider.cs index 19663da..a6faa0a 100644 --- a/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitCodegenProvider.cs +++ b/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitCodegenProvider.cs @@ -65,6 +65,8 @@ public async Task> GetJitCodegenAsync(DisasmTarg ? "" : $"-f {tfm}"; + string platformPart = GetPlatformArg(projectContext); + // Some things can't be set in CLI e.g. appending to DefineConstants var tmpProps = Path.GetTempFileName() + ".props"; File.WriteAllText(tmpProps, $""" @@ -81,7 +83,7 @@ public async Task> GetJitCodegenAsync(DisasmTarg logger.LogInformation("Running dotnet publish for reload"); string dotnetPublishArgs = - $"publish {tfmPart} -r {runtimeId} -c Release -o \"{resultOutDir}\" --self-contained true /p:PublishTrimmed=false /p:PublishSingleFile=false /p:CustomBeforeDirectoryBuildProps=\"{tmpProps}\" /p:WarningLevel=0 /p:TreatWarningsAsErrors=false -v:q"; + $"publish {tfmPart} -r {runtimeId} -c Release -o \"{resultOutDir}\" --self-contained true {platformPart} /p:PublishTrimmed=false /p:PublishSingleFile=false /p:CustomBeforeDirectoryBuildProps=\"{tmpProps}\" /p:WarningLevel=0 /p:TreatWarningsAsErrors=false -v:q"; publishResult = await ProcessUtils.RunProcessAsync(dotnetCliExePath, dotnetPublishArgs, null, projectDirPath, LogProcessOutput, cancellationToken: cancellationToken); @@ -98,6 +100,7 @@ public async Task> GetJitCodegenAsync(DisasmTarg } string dotnetBuildArgs = $"build {tfmPart} -c Release -o \"{resultOutDir}\" --no-self-contained " + + $"{platformPart} " + "/p:RuntimeIdentifier=\"\" " + "/p:RuntimeIdentifiers=\"\" " + "/p:WarningLevel=0 " + @@ -364,7 +367,9 @@ private async Task> GetJitCodegenInternalAsync(D else if (configuration.IsNonCustomNativeAotMode()) { logger.LogDebug("Compiling for NativeAOT (.NET 8.0+ is required) ..."); - + + string platformPart = GetPlatformArg(projectContext); + // For non-custom NativeAOT we need to use dotnet publish + with custom IlcArgs // namely, we need to re-direct jit's output to a file (JitStdOutFile). @@ -410,7 +415,7 @@ private async Task> GetJitCodegenInternalAsync(D // NOTE: CustomBeforeDirectoryBuildProps is probably not a good idea to overwrite, but we need to pass IlcArgs somehow string dotnetPublishArgs = $"publish {tfmPart} -r {runtimeId} -c Release" + - $" /p:PublishAot=true /p:CustomBeforeDirectoryBuildProps=\"{tmpProps}\"" + + $" {platformPart} /p:PublishAot=true /p:CustomBeforeDirectoryBuildProps=\"{tmpProps}\"" + $" /p:WarningLevel=0 /p:TreatWarningsAsErrors=false -v:q"; var publishResult = await ProcessUtils.RunProcessAsync(dotnetCliExePath, dotnetPublishArgs, null, @@ -571,6 +576,9 @@ private async Task> GetJitCodegenInternalAsync(D } } + private static string GetPlatformArg(JitDisasmProjectContext projectContext) => + string.IsNullOrEmpty(projectContext.Platform) ? "" : $"/p:Platform=\"{projectContext.Platform}\""; + private void LogProcessOutput(bool isError, string message) { if (isError) diff --git a/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitDisasmProjectContext.cs b/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitDisasmProjectContext.cs index bd4b58a..119f6bf 100644 --- a/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitDisasmProjectContext.cs +++ b/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasm/JitDisasmProjectContext.cs @@ -10,7 +10,8 @@ public record JitDisasmProjectContext( string ProjectFilePath, string ProjectDirectory, [CanBeNull] string AssemblyName, - string DotNetCliExePath) + string DotNetCliExePath, + [CanBeNull] string Platform = null) { public Result Validate() { diff --git a/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasmAdapters/JitDisasmProjectContextFactory.cs b/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasmAdapters/JitDisasmProjectContextFactory.cs index 385b6a1..2a553ce 100644 --- a/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasmAdapters/JitDisasmProjectContextFactory.cs +++ b/src/dotnet/ReSharperPlugin.DotNetDisassembler/JitDisasmAdapters/JitDisasmProjectContextFactory.cs @@ -1,5 +1,7 @@ using JetBrains.Application.Threading; using JetBrains.ProjectModel; +using JetBrains.ProjectModel.MSBuild; +using JetBrains.ProjectModel.Properties; using JetBrains.ReSharper.Feature.Services.Protocol; using JetBrains.Rider.Model; using JetBrains.Util; @@ -19,6 +21,7 @@ public static JitDisasmProjectContext Create(IProject project) var outputDirectory = tfmId != null ? project.GetOutputDirectory(tfmId) : null; var assemblyName = tfmId != null ? project.GetOutputAssemblyName(tfmId) : null; var dotNetCliExePath = GetDotNetCliExePath(solution); + var platform = project.GetUniqueRequestedProjectProperty(MSBuildProjectUtil.PlatformTargetProperty); return new JitDisasmProjectContext( Sdk: sdk, @@ -27,7 +30,8 @@ public static JitDisasmProjectContext Create(IProject project) ProjectFilePath: project.ProjectFileLocation?.FullPath, ProjectDirectory: project.Location?.FullPath, AssemblyName: assemblyName, - DotNetCliExePath: dotNetCliExePath); + DotNetCliExePath: dotNetCliExePath, + Platform: platform); }); }