Skip to content

Conversation

@jonathanpeppers
Copy link
Member

Context: #2929
Context: https://github.com/dotnet/android/blob/4aa9af89102af2e745a8507992187d3c5993d638/Documentation/guides/MSBuildBestPractices.md

In initially testing BenchmarkDotNet with .NET MAUI, I found that the weaver was not being executed because the Publish target is not called during the build process for Android and iOS projects. I think the target could actually run much sooner during builds and achieve better results.

To address this, I refactored the BenchmarkDotNet.Weaver.targets file to run after CoreCompile on the @(IntermediateAssembly) in the obj directory. This is similar to what other targets do, such as the XamlC compiler:

https://github.com/dotnet/maui/blob/8224becbb3a8a6bb1caaca4bbe70c56e88875506/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets#L213-L255

Other general MSBuild improvements:

  • Defined an MSBuild property for everything that seems useful. This allows consuming projects to configure the behavior (or workarounds!) as needed.

  • Made the MSBuild target incremental by using inputs and outputs. If the .dll file is an input, we can write a .stamp file as an output to indicate that the weaver has already been run for that assembly. If the .dll file changes, the weaver will run again.

I tested this change with a .NET MAUI on 4 platforms and also the existing BenchmarkDotNet.Samples console app.

… platforms

Context: dotnet#2929
Context: https://github.com/dotnet/android/blob/4aa9af89102af2e745a8507992187d3c5993d638/Documentation/guides/MSBuildBestPractices.md

In initially testing BenchmarkDotNet with .NET MAUI, I found that the
weaver was not being executed because the `Publish` target is not
called during the build process for Android and iOS projects. I think
the target could actually run much sooner during builds and achieve
better results.

To address this, I refactored the `BenchmarkDotNet.Weaver.targets`
file to run after `CoreCompile` on the `@(IntermediateAssembly)` in
the `obj` directory. This is similar to what other targets do, such as
the XamlC compiler:

https://github.com/dotnet/maui/blob/8224becbb3a8a6bb1caaca4bbe70c56e88875506/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets#L213-L255

Other general MSBuild improvements:

* Defined an MSBuild property for everything that seems useful. This
  allows consuming projects to configure the behavior (or
  workarounds!) as needed.

* Made the MSBuild target incremental by using inputs and outputs. If
  the `.dll` file is an input, we can write a `.stamp` file as an
  output to indicate that the weaver has already been run for that
  assembly. If the `.dll` file changes, the weaver will run again.

I tested this change with a .NET MAUI on 4 platforms and also the
existing `BenchmarkDotNet.Samples` console app.
@timcassell
Copy link
Collaborator

Thanks. I initially tried to do it after CoreCompile target, but it had some issues that I don't recall. Looks like this fixes that.

@timcassell timcassell merged commit 7cad308 into dotnet:master Dec 16, 2025
19 of 21 checks passed
@timcassell timcassell added this to the v0.16.0 milestone Dec 16, 2025
@DrewScoggins
Copy link
Member

I think this might have broken us. We have now started to see NETSDK1152 in our performance runs. Chatting with Copilot, it believes that the issue is from this change. This is its logic

Why It Breaks

  1. BenchmarkDotNet passes [/p:ArtifactsPath="..."] to MSBuild for the autogenerated project
  2. The SDK computes IntermediateOutputPath based on [ArtifactsPath], placing the weaved DLL in [{ArtifactsPath}/obj/.../]
  3. BenchmarkDotNet also sets custom OutDir/OutputPath/PublishDir paths
  4. During publish, the SDK's conflict resolution sees two DLLs with the same filename:
  5. The intermediate assembly in obj/
  6. The output assembly in the publish directory
  7. This triggers NETSDK1152

[2025/12/18 10:33:54][INFO] /home/helixbot/work/942D0884/w/A92E09B4/e/performance/tools/dotnet/x64/sdk/11.0.100-alpha.1.25618.105/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.ConflictResolution.targets(112,5): error NETSDK1152: Found multiple publish output files with the same relative path: /home/helixbot/work/942D0884/w/A92E09B4/e/performance/artifacts/obj/BenchmarkDotNet.Autogenerated/Release/MicroBenchmarks-Job-ALNHUU-1.dll, /home/helixbot/work/942D0884/w/A92E09B4/e/performance/artifacts/bin/MicroBenchmarks/Release/net11.0/MicroBenchmarks-Job-ALNHUU-1/bin/Release/net11.0/publish/MicroBenchmarks-Job-ALNHUU-1.dll. [/home/helixbot/work/942D0884/w/A92E09B4/e/performance/artifacts/bin/MicroBenchmarks/Release/net11.0/MicroBenchmarks-Job-ALNHUU-1/BenchmarkDotNet.Autogenerated.csproj::TargetFramework=net11.0]

@DrewScoggins
Copy link
Member

@jonathanpeppers
Copy link
Member Author

@DrewScoggins can you share a .binlog of the error? https://aka.ms/binlog

@timcassell
Copy link
Collaborator

@DrewScoggins How to repro? We have some toolchains that do publish, but the error doesn't occur in our tests. I'd like to add a test case for that if possible.

Also, can you see if #2935 fixes it?

@DrewScoggins
Copy link
Member

DrewScoggins commented Dec 18, 2025

@DrewScoggins
Copy link
Member

@timcassell Right now, we have only been able to repro it in our internal CI :( We will try tomorrow to get you something more targeted.

@jonathanpeppers
Copy link
Member Author

@DrewScoggins that .binlog above has 0 errors, and it seems like it successfully weaves the assembly:

image

Do you have a .binlog that includes the error?

I also authored this PR, so you should be able to get back the previous behavior (untested):

<PropertyGroup>
    <BenchmarkDotNetWeaveAssembliesAfterTargets>Build</BenchmarkDotNetWeaveAssembliesAfterTargets>
    <BenchmarkDotNetWeaveAssembliesBeforeTargets>Publish</BenchmarkDotNetWeaveAssembliesBeforeTargets>
    <BenchmarkDotNetWeaveAssemblyPath>$(TargetDir)$(TargetFileName)</BenchmarkDotNetWeaveAssemblyPath>
</PropertyGroup>

(Try putting in a Directory.Build.targets, so $(TargetDir)$(TargetFileName) will be set)

Share either a .binlog with the error (or if you have trouble with the workaround).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants