microsoft / MSBuildLocator

An API to locate MSBuild assemblies from an installed Visual Studio location. Use this to ensure that calling the MSBuild API will use the same toolset that a build from Visual Studio or msbuild.exe would.
Other
218 stars 83 forks source link

Microsoft.Build.Locator package reference in netstandard2.0 Sdk Style projects doesn't work #62

Closed DevKumar4Git closed 5 years ago

DevKumar4Git commented 5 years ago

In a netstandard2.0 Sdk Style projects, try to install Microsoft.Build.Locator nuget package. In the code file, try using Microsoft.Build.Locator

Why do I need this?

  1. I have a command line tool which is Net Framework & Net Core
  2. I need to access MSBuild project capabilities using Microsoft.Build.* dll in one of the net standard libraries.
  3. If I have to put MSBuildLocator.RegisterDefaults(), I would load MSBuild defaults unnecessarily in the full app & not when its actually needed in 1 library.

Is there any good workaround for this, other than packaging the MsBuild dll's with my App.

rainersigwald commented 5 years ago

Locator does not support .NET Standard, because it only supports two concrete implementations of MSBuild: netcoreapp2.0 and net46 (net472 for 16.0). That means you can't successfully run it from an arbitrary netstandard2.0-compatible application.

For your multitargeting scenario, you'll need to multitarget to .NET Framework and .NET Core, like the sample app:

https://github.com/Microsoft/MSBuildLocator/blob/bd25ad7a95d3e7f49403a1e597b2029f1e08367f/samples/BuilderApp/BuilderApp.csproj#L5

  1. If I have to put MSBuildLocator.RegisterDefaults(), I would load MSBuild defaults unnecessarily in the full app & not when its actually needed in 1 library.

Can you rephrase this, please? I don't understand what you're saying.

DevKumar4Git commented 5 years ago

Thanks for the response. Let me rephrase 3. Its mostly performance hits my app has to take in doing this.

  1. As per the documentation, I need to ship Build.Locator with my app & call MSBuildLocator.RegisterDefaults() in App Load
  2. Since I have a console app, this would mean calling in when Main is called.
  3. There are only few 2 commands in my exe which need MSBuild capability to read project files a.exe command1 arg0 ..
  4. But all 50+ commands which don't need this capability, would still invoke this MSBuildLocator.RegisterDefaults() & take perf hit.
rainersigwald commented 5 years ago

You only have to call Register before calling any function that uses a type defined in an MSBuild assembly. You could call it in your subcommand.

DevKumar4Git commented 5 years ago

That subcommand is built as a Net Standard 2.0 Library.

rainersigwald commented 5 years ago

Why is that a hard requirement?

DevKumar4Git commented 5 years ago

Its the way its built to work on Net Framework & Net Core, both using the same libraries. All the commands, sub commands are Net Standard 2.0 library & the app is just a wrapper calling it. Based on what you are suggesting, sounds like I would have to move the verbs out of Net Standard library.

rainersigwald commented 5 years ago

Yes, to evaluate MSBuild projects, you'll have to specialize the library. A single implementation cannot work in both .NET and .NET Core.

mwpowellhtx commented 4 years ago

Following on from our duplicate issue, to be clear, yes, we understand the difference between API surface area versus run time. We are talking about exposing it as an API surface area, whatever the ultimate run time might be. That's the point.

That means you can't successfully run it from an arbitrary netstandard2.0-compatible application.

A statement like this causes me to wonder whether there isn't confusion upstream from your subscribers. We are not trying to run anything from the API surface area. But we are working on managers or other scaffolds that stitch the experience together that eventually does get invoked by a run time, in a test environment, in an actual CLI tooling, or other run time environment.

sharwell commented 4 years ago

@mwpowellhtx If I understand you correctly, you are looking for this:

  1. A project CommonImplementation.dll targets netstandard2.0. This project references Microsoft.Build.Locator and makes a call to MSBuildLocator.RegisterDefaults().
  2. Since CommonImplementation.dll doesn't actually do anything by itself (it's a shared library with no entry point), you create another project Host.exe. This project targets concrete frameworks, and can either single-target or multi-target. It references CommonImplementation and makes a call into it which eventually leads to the RegisterDefaults() call.

You are asking for this scenario to work by providing the following:

  1. Microsoft.Build.Locator provides two (or more) implementation assemblies (in the lib folder of the NuGet package), with one for each supported target framework, (e.g. net472 and netcoreapp2.0 would be two of these).
  2. Microsoft.Build.Locator provides an additional reference assembly (in the ref folder of the NuGet package) for netstandard2.0. This assembly is not executable, but can be used by a library targeting netstandard2.0 to defer the decision about which implementation assembly to use to the project that eventually calls into the library.
mwpowellhtx commented 4 years ago

@sharwell Along these lines, yes, I think so. But if I understand correctly, there are dependencies that Locator leverages which themselves are run time only targets. If we have a naive notion of the scope, fair enough. I'm just stating the intended, expectation. Whether that's practical, attainable, is another question.