Skip to content
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

Convert C# Reference Assembly Generation to Use GenAPI #1057

Merged
merged 86 commits into from
Jun 24, 2019

Conversation

rladuca
Copy link
Member

@rladuca rladuca commented Jun 22, 2019

Fixes #932

What work is currently in this PR:

GitHub

  • For all shipping C# reference assemblies built on GitHub generate their code from GenAPI
  • Fixup any issues that result from GenAPI code gen (see ManualFixups.txt in this PR)
  • Baseline all ApiCompat issues (there is a feedback loop here with fixups for a few commits)

dotnet-wpf-int

  • Switch ProjectReference substitution for dotnet-wpf-int to use runtime assemblies
  • For all shipping C# reference assemblies built on dotnet-wpf-int generate their code from GenAPI
  • Fixup any issues that result from GenAPI code gen (see ManualFixups.txt in this PR)
  • Baseline all ApiCompat issues (there is a feedback loop here with fixups for a few commits)

Testing Work:

  • Build our internal test corpus against new ref assemblies
  • Build our samples repo against new ref assemblies
  • Build NuGet Package Explorer against new ref assemblies
  • Verify there are no dangling references to assemblies not part of the reference pack

What you should center your review around

  • Engineering system changes (in WpfArcadeSdk, ignore Arcade DARC flow)
  • ApiCompat results and baselines
  • Exclusion lists for GenApi (see GlobalApiExclusions.txt and GlobalAttrExclusions.txt)

These are what eventually feed into the reference assemblies and dictate the public surface area.

Links

dotnet-wpf-int PR: https://dev.azure.com/dnceng/internal/_git/dotnet-wpf-int/pullrequest/1772?_a=overview

Upstream notification issue: https://github.com/dotnet/core-setup/issues/6901

rladuca and others added 30 commits June 13, 2019 11:26
Disabling use of ProduceReferenceAssembly across the codebase.
…nces. Otherwise we can potentially import at incorrect times, overriding various values from the WpfArcadeSdk.
… the runtime assembly's project as a template. Based on PBT's GenerateTemporaryTargetAssembly.
Removing EmbeddedResources from reference assemblies.
File dumping the initial generated code and projects.
Changes to ensure that reference assembly projects are properly bin placed into the ref pack.
…ally fixed output for WindowsBase reference assembly.
@rladuca
Copy link
Member Author

rladuca commented Jun 22, 2019

.NET Framework reference assemblies contain resources (BAML/strings resx, etc). Should we also include these in .NET Core?

@rladuca rladuca changed the title WIP Convert C# Reference Assembly Generation to Use GenAPI Convert C# Reference Assembly Generation to Use GenAPI Jun 22, 2019
Copy link
Contributor

@stevenbrix stevenbrix left a comment

Choose a reason for hiding this comment

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

In your description you mention a "ManualFixups.txt" file in the PR, but i don't see that anywhere. was that removed or changed to a different file name?

When a build is run with that property enabled, GenAPI will read the runtime assembly and generate a new `{AssemblyName}.cs` file under the ref directory in the assembly's source tree.

This new file will contain the newly created surface area and will need to be checked in along with the runtime assembly change. The next build without `GenerateReferenceAssemblySource` enabled will no longer display an ApiCompat error as the surface area will now match the baseline.
### Issues with GenAPI
Copy link
Contributor

Choose a reason for hiding this comment

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

is all of this extra work needed because we use the InternalsVisibleToAttribute?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a combination of a few things, InternalsVisibleTo certainly complicates things between assemblies, but also XAML compilation will reflect and try to find internal API in order to take certain shortcuts and optimizations. (Look at IAddChildInternal for example).

There are also issues where we have public API that has internal abstract members, which confuses GenAPI. GenAPI itself just sometimes adds strange things, like private dummy int fields and properties. No idea why, there are just bugs. I intend to make small reproduction applications when I have time and file bugs against GenAPI, but that's future stuff.

Choose a reason for hiding this comment

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

Are those bugs reported back to the Roslyn team so they can be fixed?

Copy link
Member Author

Choose a reason for hiding this comment

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

GenAPI doesn't use Roslyn it uses Microsoft.CCI). Originally, we were using Roslyn to generate our reference assemblies, but the use of InternalsVisibleTo was creating dangling references. We filed dotnet/roslyn#36409 to address these issues. In the meantime, this was the fix.

I haven't created issues against GenAPI yet, I haven't had the time to create minimal reproductions of the various bugs.

Copy link
Contributor

Choose a reason for hiding this comment

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

If i'm adding a new function to a class, what's the difference between adding the API to the reference assembly manually and using GenAPI? I might not fully understand the problem we are trying to solve here, but it seems like it would be much simpler to just manually modify the reference assembly. Is there some part of our workflow that makes things more complicated?

Copy link
Member Author

Choose a reason for hiding this comment

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

I missed this. The C# reference assemblies didn't exist in a manual fashion before this (back in the old internal repo maybe), so we could not just add things. So GenAPI was used as an initial seed for the most part. For some changes, it's probably easy enough just to pop the change into the reference assembly. Other changes it might be more difficult and require basically mirrored code changes. Also if you make a small change sans GenAPI then someone makes a very large change and uses it, it'll likely generate a noisier diff since your code location might not be the same.

It's probably the simplest and most thorough to GenAPI and use that output to manually add to the reference assembly. It's pretty easy (mostly) to diff the generated output against the current surface and just pick and choose your new stuff.

Long term we'd rather just have Roslyn allow us to say, "All publics, but also these specific internals" in a nice configurable fashion and call it a day. But we need something in the short term.

@rladuca
Copy link
Member Author

rladuca commented Jun 23, 2019

In your description you mention a "ManualFixups.txt" file in the PR, but i don't see that anywhere. was that removed or changed to a different file name?

I removed it from the docs and the repo. Basically, it would confuse more than help in light of some internals needing to be kept for XAML compilation.

I decided it's just best to tell developers to selectively add your change (as generated by GenAPI) and ignore the other fluff. We can work on improving the output from GenAPI in terms of the cleanup, but it's not there just yet.

@vatsan-madhavan
Copy link
Member

.NET Framework reference assemblies contain resources (BAML/strings resx, etc). Should we also include these in .NET Core?

No, let's not include these.

* Extract just the new surface area (and related code) from the generated code
* Revert the generated file
* Add back the new surface area to the reference assembly code
* Ensure that nothing in the new surface area is private or internal unless requried by XAML compilation or other reference assemblies
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't sound like a good idea to have internal/private APIs required by the XAML compiler. I understand that IAddChildInternal exists today, but is this something we want to put in as being an ok thing to do in the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is more if you make a change to an existing class that uses something like that, the entire class will get re-generated, sans the IAddChildInternal. So you need to ensure that you're not messing with that piece.

Copy link
Member Author

Choose a reason for hiding this comment

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

We can have a discussion about fixing the docs up later, at this point I don't want to spin another build just due to doc updates. Helix queues are killing me today.

@rladuca rladuca merged commit 422c8df into master Jun 24, 2019
@rladuca rladuca deleted the dev/roladuca/genapics branch June 27, 2019 00:20
@ghost ghost locked as resolved and limited conversation to collaborators Apr 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
PR metadata: Label to tag PRs, to facilitate with triage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Convert C# Reference Assembly Generation to Use GenAPI
5 participants