Skip to content

Add 'RunCsWinRTGenerator' task and target #49417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Sergio0694
Copy link
Contributor

This PR adds supporting infra for CsWinRT 3.0 (see here):

  • A RunCsWinRTGenerator task that runs cswinrtgen
  • A target that loads and invokes the task as needed

Everything is opt-in and off-by-default.


<!-- Default property values for 'cswinrtgen' -->
<PropertyGroup>
<CsWinRTToolsDirectory Condition="'$(CsWinRTToolsDirectory)' == ''"></CsWinRTToolsDirectory>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we need to get the path to the root directory of the Microsoft.Windows.SDK.NET.Ref package that's going to be used. Not sure how to get it from here though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a packageref to this package (implicit or explicit), there may be a PackagePath_MIcrosoft_Windows_SDK_NET_Ref MSbuild property already ambiently available. Check a binlog and see?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried in a blank app targeting net9.0-windows10.0.26100.0, not seeing that variable 🥲
Is this something we could configure in the .NET SDK? Since it's the one adding this 🤔


<!-- Add the interop .dll to the list of reference paths -->
<ItemGroup>
<ReferencePath Include="@(CsWinRTGeneratorInteropAssemblyPath)" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need two things here:

  • @(CsWinRTGeneratorInteropAssemblyPath) needs to be copied to the output directory
  • @(CsWinRTGeneratorInteropAssemblyPath) also needs to be added to .deps.json

I'm not sure how to do both. I could do it by adding the item to both ReferencePath, UserRuntimeAssembly, and IntermediatePath, but that doesn't seem correct. What is the right way to achieve this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need to look into answers for both of these, I'll try to do that tomorrow.

============================================================
-->
<UsingTask Condition="'$(CsWinRTGeneratorTasksOverriden)' != 'true'" TaskName="RunCsWinRTGenerator" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />
<Target
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, this target would only run if something changed. As in, if there's been any code changes or if any transitive dependency changed. I'm assuming the Csc task that's invoked in CoreCompile would already be doing some kind of check like that, to skip work if eg. you just F5 again without changing anything. Is there a way for us to perform the same check (or get that result out of CoreCompile) so we can also skip this target if not needed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This concept is known as incrementality. The short form is that if you know your inputs, and your inputs are files whose timestamps can be tracked, then you can set Inputs=..all that stuff.. on your Target and the MSBuild engine will transparently track them and only call your target if any of them are out of date. Similarly, if you know your Outputs, you can provide those to the engine as well and up-to-date checking will take place.

This means that many complex Targets often have a 'compute the inputs and outputs for Target XXXXX' Target that runs immediately before them, so that you can compute the correct set of inputs/outputs for incrementality purposes.

Copy link
Contributor Author

@Sergio0694 Sergio0694 Jun 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I added the Inputs property. I have a couple more questions though:

  • I don't know the exact output path in advance, as that's computed by the target. I get that via that CsWinRTGeneratorInteropAssemblyPath item that the target produces as output. Is there a way to configure that returned item as the Outputs item for the wrapping task?
  • I also need to re-run the target if any of the other input properties changes. The docs seem to only talk about input/output items. How can one handle incrementality with respect to properties as well? 🤔

Thank you!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the first point, we usually try to have those paths be able to be input into the Task to help with this kind of incrementality.
For the second, this is a gap in the MSBuild Incrementality model - it only supports files today. To get around this, most people have a 'generate property cache file' Target that they have run immediately before their real Target and they add this generated file to their Inputs. You can see an example of this pattern here.

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.

2 participants