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

Return SDKs from all dotnet location #329

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

Conversation

JoeRobich
Copy link
Member

@JoeRobich JoeRobich commented Mar 19, 2025

Review with whitespace off as the formatter removed trailing whitespace.

The method which finds all SDKs has an early exit which stops it from finding SDKs from more than one dotnet install. This PR removes the early exit and filters the returned instances by their reported version number. This should deduplicate the SDKs.

{
break;
}
NativeMethods.hostfxr_get_available_sdks(exe_dir: dotnetPath, result: (key, value) => resolvedPaths = value);
Copy link
Member

Choose a reason for hiding this comment

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

How about this?

Suggested change
NativeMethods.hostfxr_get_available_sdks(exe_dir: dotnetPath, result: (key, value) => resolvedPaths = value);
int rc = NativeMethods.hostfxr_get_available_sdks(exe_dir: dotnetPath, result: (key, value) => resolvedPaths = value);
if (rc == 0 && resolvedPaths != null && resolvedPaths.Length > 0)
{
foreach (string path in resolvedPaths)
{
yield return path;
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, thanks in my head it was accumulating them but I see now it isn't. Will update.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated.

Copy link
Member

Choose a reason for hiding this comment

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

Definitely a bit confusing with how the native APIs work 🙂 I struggled with that for a bit when I wrote the first version of this.

{
string? bestSdkPath;
string[] allAvailableSdks;
try
Copy link
Member Author

Choose a reason for hiding this comment

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

Inlined GetDotNetBasePaths

string? bestSDK = GetSdkFromGlobalSettings(workingDirectory);
if (!string.IsNullOrEmpty(bestSDK))
// Returns the list of all available SDKs ordered by ascending version.
static string[] GetAllAvailableSDKs()
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 method and GetSdkFromGlobalSettings were only referenced from the inlined GetDotNetBasePaths so I made them local functions.

for (int i = dotnetPaths.Length - 1; i >= 0; i--)
{
if (dotnetPaths[i] != bestSDK)
if (rc == 0 && resolvedPaths != null)
Copy link
Member Author

Choose a reason for hiding this comment

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

Previous behavior was that we would not throw if resolvedPaths was an empty array.

Copy link
Member

@Forgind Forgind left a comment

Choose a reason for hiding this comment

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

I think this would work the way I'd expect! @baronfel mentioned a concern about diverging from dotnet.exe's behavior in not using other dotnet.exes, but I would want to better understand his reasoning, as I'd argue that MSBuildLocator is (and always has been) more flexible with respect to which MSBuild it ultimately loads than dotnet.exe is, so I see no reason it shouldn't also be more flexible as far as which it finds. That said, we should still solicit feedback from MSBuild, as I don't actually own this product 🙂

Comment on lines +103 to +107
// Only add an SDK once, even if it's installed in multiple locations.
if (!versionInstanceMap.ContainsKey(dotnetSdk.Version))
{
versionInstanceMap.Add(dotnetSdk.Version, dotnetSdk);
}
Copy link
Member

Choose a reason for hiding this comment

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

Tiny nit:
I think we can skip to:

Suggested change
// Only add an SDK once, even if it's installed in multiple locations.
if (!versionInstanceMap.ContainsKey(dotnetSdk.Version))
{
versionInstanceMap.Add(dotnetSdk.Version, dotnetSdk);
}
// Only add an SDK once, even if it's installed in multiple locations.
versionInstanceMap[dotnetSdk.Version] = dotnetSdk;

(One fewer dictionary access)

Copy link
Member Author

Choose a reason for hiding this comment

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

So I am unsure if it is a benefit or not, by keeping the first SDK for each discovered version we maintain a preference for SDKs in the following install location ordering.

  1. DOTNET_ROOT
  2. Current process path if MSBuild.Locator is called from dotnet.exe
  3. DOTNET_HOST_PATH
  4. DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR
  5. PATH

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