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

Switch MSBuildWorkspace to running builds out of proc #70469

Conversation

jasonmalinowski
Copy link
Member

@jasonmalinowski jasonmalinowski commented Oct 19, 2023

This switches MSBuildWorkspace over to using out-of-proc builds using the same mechanism we use for our LSP process. This brings a few advantages:

  1. Applications on .NET Framework can now analyze .NET Core projects and vice versa without special work on the application author's side. Today your best workaround is to do something like multi-target your app for both platforms and hope the user knows which one to pick.
  2. It ensures we're better isolated from the application's deployed binaries. For example, applications could now deploy MSBuild as a regular library without breaking MSBuildLocator (since that's not needed in proc), which simplifies things like our LSIF generator. This also fixes Workspace failed with could not load "NuGet.Frameworks" error #61454 (and similar bugs) where an extra binary being deployed can potentially break MSBuild. There's further isolation work to still do here, to ensure we're more isolated even against what the BuildHost ships, but since it means the environment for running stuff is far more controlled, we'll have more confidence of what we test in our own tests will represent the behavior in the wild.
  3. It ensures that the user doesn't have to worry about things like MSBuildLocator or binding redirects, etc. For example, we always have a non-stop stream of questions on StackOverflow of people having issues this way and those are fixed for good.

The one major caveat here is we did have some entrypoints for MSBuildWorkspace that accept an ILogger; currently these will be broken. I'm still reaching out to folks to decide what to do here. We can simply obsolete them, or try to get them to work in a few scenarios. (For example, I could detect if the logger you passed is a well known built in logger we can just recreate that on the OOP side). This will also break any apps that were really expecting the build to be in-proc (like by tinkering with MSBuild properties in advance) but such a behavior wasn't really supported anyways.

Work still to do prior to merge:

  • Add support back for TryApplyChanges; I have that commented out at the moment while I got the core stable first.
  • Replace StreamJsonRpc with a different RPC mechanism since that's not source build friendly.
  • Fix some bugs around locked/corrupted project files that the new code isn't dealing with as well.
  • Add support back for setting properties like debug/release configurations.
  • Write a bunch more tests for the StreamJsonRpc replacement.

Things that will be tracked for follow-up:

  • Right now we are shipping two BuildHost layouts as a part of any use, which means duplicating the BuildHost and all it's references twice. We can definitely trim down number of binaries to reduce the disk size. For example we're shipping Microsoft.CodeAnalysis.Workspaces and Microsoft.CodeAnalysis mostly for various helpers or trivial enums that we could either link or just remove.
  • Investigate the logic of MSBuildWorkspace's support for adding documents, which seems to be repeatedly converting between relative and absolute paths.
  • Unit tests for metadata reference removal, since there aren't any today.
  • More formally obsolete the ILogger APIs.
  • Switching the OOP serialization to System.Text.Json so that way we're not shipping Newtonsoft.Json. Ironically we're shipping both libraries at the moment...

@jasonmalinowski jasonmalinowski self-assigned this Oct 19, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 19, 2023
@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch 4 times, most recently from 84d5350 to 1fa1478 Compare October 26, 2023 00:22
@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch 2 times, most recently from 070b828 to 52be409 Compare October 28, 2023 00:07
Comment on lines -39 to -44
#if NETCOREAPP
// This property ensures that XAML files will be compiled in the current AppDomain
// rather than a separate one. Any tasks isolated in AppDomains or tasks that create
// AppDomains will likely not work due to https://github.com/Microsoft/MSBuildLocator/issues/16.
{ "AlwaysCompileMarkupFilesInSeparateDomain", bool.FalseString },
#endif
Copy link
Member Author

@jasonmalinowski jasonmalinowski Oct 28, 2023

Choose a reason for hiding this comment

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

If this is still necessary, it doesn't belong in this assembly anymore since the "is this .NET Core?" test should be in a different process. (And if it's generally necessary for XAML projects, then we should have this as a central fix.)

@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch 3 times, most recently from 6d3d5c9 to 6478bf9 Compare November 1, 2023 21:56
Some of the strings were used in the build host, and some were used
by the main library; this splits them in preparation for removing the
project reference entirely.
@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch 2 times, most recently from ea08f53 to ebd68d6 Compare November 3, 2023 00:16
@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch from ebd68d6 to e7f2950 Compare November 4, 2023 00:47
<Output TaskParameter="TargetOutputs" ItemName="BuildOutputInPackage" />
</MSBuild>
</Target>
<Target Name="GetBuildHostDebugSymbols">
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 can't figure out what scenario symbol packing was happening in, so just removing it.

@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch 2 times, most recently from 62e635c to 79bfce5 Compare November 7, 2023 03:10
@jaredpar jaredpar self-assigned this Nov 7, 2023
@jasonmalinowski jasonmalinowski marked this pull request as ready for review November 8, 2023 01:15
@jasonmalinowski jasonmalinowski requested review from a team as code owners November 8, 2023 01:15
Comment on lines -225 to -229
<!--
The package "Microsoft.CodeAnalysis.Analyzer.Testing" brings in an earlier version of these NuGet dependencies than
is expected by the NET SDK used in the Workspace.MSBuild UnitTests. In order to test against the same verion of NuGet
as our configured SDK, we must set the version to be the same.
-->
Copy link
Member Author

Choose a reason for hiding this comment

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

NuGet dependencies don't matter anymore, so this workaround can be removed for good.

Copy link
Member

Choose a reason for hiding this comment

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

this makes me very happy :)

Comment on lines +58 to +60
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsoleVersion)" />
Copy link
Member Author

Choose a reason for hiding this comment

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

These were implicitly coming along with the BuildHost ProjectReference, but now it's just explicit.

@@ -12,7 +12,6 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetVersion)" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="$(BenchmarkDotNetDiagnosticsWindowsVersion)" />
<PackageReference Include="Microsoft.Build.Locator" Version="$(MicrosoftBuildLocatorVersion)" />
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 PR generally goes through the repo and removes uses of MSBuild Locator that was used in places that were using MSBuildWorkspace. Those just aren't necessary anymore.

This binary is implicitly a dependency of the Razor source generator,
so needs to be present for any time the generator is running and is
running in design time mode. That's not going to happen usually but
would happen in any MSBuildWorkspace scenario.
The tests we have here were testing the underlying code by directly
creating loggers, but we don't have an MSBuild in process anymore for
those tests to work. Rather than having a BuildHost specific test bed
we'll just change the tests to test the end-to-end.
On .NET Framework, Path APIs in very invalid paths throw exceptions.
On .NET Core, they do something reasonable and then you might just
FileNotFound later when the file doesn't exist. This updates the
tests accordingly.
We'll still keep the .NET Core build host around, since the process
isolation still ensures binaries deployed as a part of the application
don't break MSBuild.
Referencing Microsoft.Extensions.Logging.Abstractions breaks source
build because 6.0.2 isn't available. But 6.0.0 is so we can just use
that.
If it's already crashed and exited, then there's no point in trying
to shutdown communication with it -- it's already gone.
If the process is dead we shouldn't be trying to send an RPC to it.
When we dispose a process, it fires events which causes us to remove
it from the map.
@jasonmalinowski jasonmalinowski force-pushed the move-msbuildworkspace-builds-out-of-proc branch from dd359c6 to a1f6b59 Compare November 14, 2023 01:53
@jasonmalinowski jasonmalinowski merged commit 5b73439 into dotnet:main Nov 14, 2023
27 checks passed
@jasonmalinowski jasonmalinowski deleted the move-msbuildworkspace-builds-out-of-proc branch November 14, 2023 03:25
@ghost ghost added this to the Next milestone Nov 14, 2023
@jasonmalinowski
Copy link
Member Author

I'll be making a GitHub project later this week to track the follow-up work to this PR.

@RikkiGibson RikkiGibson modified the milestones: Next, 17.9 P2 Nov 28, 2023
akoeplinger added a commit to dotnet/hotreload-utils that referenced this pull request Apr 8, 2024
MSBuildLocator is no longer needed since dotnet/roslyn#70469 and the workarounds for NuGet.Framework can be removed too.
dotnet-maestro bot added a commit to dotnet/hotreload-utils that referenced this pull request Apr 9, 2024
[main] Update dependencies from dotnet/roslyn, nuget/nuget.client


 - Add dependency on Microsoft.Extensions.Logging 8.0.0

match the version that roslyn wants
dotnet/roslyn#71916

 - Revert "Add dependency on Microsoft.Extensions.Logging 8.0.0"

This reverts commit f947f38.

 - Add temporary reference to Microsoft.Extensions.Logging 8.0.0

 - Cleanup dependencies, remove MSBuildLocator

MSBuildLocator is no longer needed since dotnet/roslyn#70469 and the workarounds for NuGet.Framework can be removed too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Workspace failed with could not load "NuGet.Frameworks" error
8 participants