Skip to content

Enable 'dotnet sdk check' command in AOT native binary#54391

Open
NikolaMilosavljevic wants to merge 3 commits into
dotnet:mainfrom
NikolaMilosavljevic:aot3
Open

Enable 'dotnet sdk check' command in AOT native binary#54391
NikolaMilosavljevic wants to merge 3 commits into
dotnet:mainfrom
NikolaMilosavljevic:aot3

Conversation

@NikolaMilosavljevic
Copy link
Copy Markdown
Member

Summary

Enables the dotnet sdk check command to run in the AOT-compiled native CLI binary, improving cold-start performance for this command.

Changes

  • Parser.cs: Register sdk check command in the #if CLI_AOT section with SdkCheckCommand.Run action
  • dotnet-aot.csproj: Add compile items (CommandBase, PrintableTable, 6 sdk-check files), embedded resources (CliStrings.resx, CliCommandStrings.resx), and Microsoft.Deployment.DotNet.Releases package reference
  • NativeEntryPoint.cs: Extract ExecuteCore method so the entire [UnmanagedCallersOnly] entry point body is wrapped in a top-level try/catch — no managed exception can cross the unmanaged boundary. Also sets Program.DotnetRoot and adds inner exception handling for AOT invoke path.
  • Program.cs: Add Program.DotnetRoot static property (AOT-only) to thread host-provided dotnet root to commands; add try/catch in Main
  • CommandBase.cs: Guard ParseResultExtensions import and ShowHelpOrErrorIfAppropriate call with #if !CLI_AOT (these depend on types not available in AOT build)
  • SdkCheckCommand.cs: Conditional extern alias, conditional EnvironmentProvider using, thread Program.DotnetRoot in AOT path

Design Decisions

  • sdk check was chosen as the first new AOT command because it has zero MSBuild/NuGet dependencies and does all work in-process (HTTP fetch + JSON parsing + table formatting)
  • Microsoft.Deployment.DotNet.Releases uses JsonDocument DOM API (no reflection) — verified AOT-safe
  • Full CliStrings.resx and CliCommandStrings.resx are embedded (size tradeoff for simplicity over splitting ~20 needed strings)
  • NativeEntryPoint.Execute wraps the entire method body in try/catch since [UnmanagedCallersOnly] methods must never let managed exceptions escape

Known Compromises

  • dotnet sdk (bare) shows minimal System.CommandLine error vs full help in non-AOT
  • Localization may be English-only in AOT binary (satellite assembly availability depends on publish layout)
  • No AOT-specific smoke tests added yet (no existing test infra for AOT binary)

Testing

Copilot AI review requested due to automatic review settings May 20, 2026 20:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enables the dotnet sdk check command to run via the NativeAOT-compiled CLI fast-path, threading the host-provided DOTNET_ROOT into the command and hardening the unmanaged entry point so managed exceptions cannot escape across the boundary.

Changes:

  • Registers sdk check in the AOT-only parser and wires it to SdkCheckCommand.Run.
  • Extends the dotnet-aot project to compile/link the sdk check implementation and embed required .resx resources plus the Microsoft.Deployment.DotNet.Releases dependency.
  • Refactors the AOT native entry point to wrap the full [UnmanagedCallersOnly] method body in a top-level try/catch, and introduces Program.DotnetRoot (AOT-only) for passing the dotnet root into commands.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Cli/dotnet/Program.cs Adds AOT-only DotnetRoot and wraps AOT Main in error handling.
src/Cli/dotnet/Parser.cs Registers sdk check under the AOT parser.
src/Cli/dotnet/Commands/Sdk/Check/SdkCheckCommand.cs Adds AOT conditional wiring to pass Program.DotnetRoot and adjusts aliasing for AOT builds.
src/Cli/dotnet/CommandBase.cs Guards help/error extension usage for AOT builds.
src/Cli/dotnet-aot/NativeEntryPoint.cs Extracts ExecuteCore and wraps the unmanaged entry point body with a top-level try/catch; sets Program.DotnetRoot for the AOT fast-path.
src/Cli/dotnet-aot/dotnet-aot.csproj Includes sdk check sources/resources and adds Microsoft.Deployment.DotNet.Releases package reference.
Comments suppressed due to low confidence (1)

src/Cli/dotnet/Parser.cs:37

  • This error message is hard-coded even though a localized resource exists (CliStrings.RequiredCommandNotPassed). Please use the resource string here to keep messages consistent and localizable (and since CliStrings.resx is embedded for AOT in this PR).
        sdkCommand.SetAction(parseResult =>
        {
            parseResult.InvocationConfiguration.Error.WriteLine("Required command was not provided.");
            return 1;

Comment thread src/Cli/dotnet/Parser.cs
Add the sdk check command to the AOT-compiled CLI binary (dotnet-aot.csproj).
This command lists installed SDKs and runtimes and checks for updates,
performing all work in-process without MSBuild or NuGet dependencies.

Changes:
- Register 'sdk check' command in the AOT Parser.cs section
- Add exception handling in both Program.Main and NativeEntryPoint for
  GracefulException and unexpected errors
- Thread dotnetRoot from native host into SdkCheckCommand to ensure
  the correct .NET installation is inspected
- Guard CommandBase.ShowHelpOrErrorIfAppropriate with #if !CLI_AOT
  (extension method references types unavailable in AOT)
- Handle extern alias for EnvironmentProvider conditionally in
  SdkCheckCommand (#if CLI_AOT uses direct reference)
- Add Compile items, EmbeddedResource items (CliStrings.resx,
  CliCommandStrings.resx), and Microsoft.Deployment.DotNet.Releases
  package reference to dotnet-aot.csproj

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants