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

Question: clarification on usage of MSBuildLocator #320

Closed
Flandini opened this issue Dec 13, 2024 · 3 comments
Closed

Question: clarification on usage of MSBuildLocator #320

Flandini opened this issue Dec 13, 2024 · 3 comments

Comments

@Flandini
Copy link

Flandini commented Dec 13, 2024

Hi!

I am working on a C# console application that loads C# solutions and projects and does some analysis on these. I have been trying to use MSBuildLocator to load the MSBuild.*.dll files that would be actually used to run the build for a project during a normal build on a user's machine. My reasoning is that I would prefer the projects be loaded as close to their normal build as possible so my analysis is not wildly off. I really just want the build loaded similar to a normal build with all package references and project references already loaded, without actually running a compilation, and it seems I can get that using MSBuildLocator and then MsBuildWorkspace in Roslyn.

I am shipping my console application as a .NET 6 self contained release, but I am noticing that if someone else runs my application on their machine that does not have .NET 6 SDK installed, but maybe a newer .NET, then MSBuildLocator does not want to use any of the MSBuild.*.dll files on their machine because of this check in DotNetSdkLocationHelper.cs:

// Components of the SDK often have dependencies on the runtime they shipped with, including that several tasks that shipped
// in the .NET 5 SDK rely on the .NET 5.0 runtime. Assuming the runtime that shipped with a particular SDK has the same version,
// this ensures that we don't choose an SDK that doesn't work with the runtime of the chosen application. This is not guaranteed
// to always work but should work for now.
if (!allowQueryAllRuntimeVersions && 
       (major > Environment.Version.Major || 
        (major == Environment.Version.Major && minor > Environment.Version.Minor)))
{
    return null;
}

I see that this could be disabled by setting MsBuildLocator.AllowQueryAllRuntimeVersions, and in 1.7.8, this flag seems to only affect that above check, but then the loading of other dependencies like System.Runtime.dll fail after, so this is a non-option. I get this error message:

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Could not load file or assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

I also see other workarounds like that in this related issue nuke-build/nuke#933, but since my workaround and theirs should both load the same non-.NET 6 .dlls in this scenario, I think this other workaround will still not work for my app.

My questions are:

  1. Is there some pattern of usage for MSBuildLocator that I am missing? I saw some references that hint at maybe needing to put all of the MSBuild-related code in a separate process?
  2. Is it intended that I need to target the latest .NET SDK version for my application in order for it to use MSBuildLocator on other machines? If I change to shipping my app as a .NET 9 self-contained console app, then everything works fine even if MSBuildLocator loads the assemblies from, e.g., a .NET 7 SDK on the user's machine, but this same situation doesn't work if I ship my app as a .NET 6 app.

Thanks in advance :)

@Flandini
Copy link
Author

I found this for question 2: #195. I am guessing this means yes to the second question? I don't know enough about MSBuild and the .NET ecosystem, but could someone tell me then if targeting the latest .NET SDK for my app would make it safe for my app to load all previous .NET SDK MSBuild.*.dll files?

@YuliiaKovalova
Copy link
Contributor

Hello @Flandini,

Your observation about MSBuildLocator's version compatibility is correct.
The best solution is to target the latest .NET SDK version in your self-contained application.
This ensures:

  • Broader compatibility with previous SDK versions
  • Simplified dependency management
  • Reduced runtime loading issues

By shipping your app as a .NET 9 (or latest) self-contained console app, you'll resolve the MSBuild assembly loading challenges you're experiencing with .NET 6. Just because if you are on .NET 6 we can't see future and resolving any higher version is problematic and error prone.

That's why the current MSBuildLocator design intentionally restricts loading SDKs with runtime versions newer than the current application to prevent potential compatibility issues.

@Flandini
Copy link
Author

Ok, thanks for the confirmation @YuliiaKovalova!

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

No branches or pull requests

2 participants