Skip to content

Enable AOT-compiled SDK tools in source-build - #7300

Merged
mthalman merged 3 commits into
dotnet:mainfrom
mthalman:dev/mthalman/aot-sdk-tools-source-build
Jun 30, 2026
Merged

mthalman merged 3 commits into
dotnet:mainfrom
mthalman:dev/mthalman/aot-sdk-tools-source-build

Conversation

@mthalman

Copy link
Copy Markdown
Member

The SDK bundles three ASP.NET Core CLI tools (dotnet-dev-certs, dotnet-user-jwts, dotnet-user-secrets) as a Native AOT aggregate, but AOT publishing of these tools only worked in the Microsoft build. In source-build it failed in two ways: restore could not find a portable-RID runtime pack (NU1102), and once scoped to the build's non-portable RID the previous SDK rejected the project with NETSDK1203 ("Ahead-of-time compilation is not supported for the target runtime identifier"). The root cause is that every repo in the VMR builds against a previous SDK; in a stage 1 source-build leg that SDK is the Microsoft portable SDK, whose bundled props do not list the build's non-portable RID (e.g. centos.10-x64) in the ILCompiler/runtime-pack RID sets and whose packs/ folder has no NativeAOT pack for that RID.

Teach the previous SDK about the source-built non-portable RID and unblock AOT publishing, then ship the resulting aggregate in source-build. Fixes dotnet/source-build#5567.

Also dependent on #7297

The SDK bundles three ASP.NET Core CLI tools (dotnet-dev-certs, dotnet-user-jwts,
dotnet-user-secrets) as a Native AOT aggregate, but AOT publishing of these tools
only worked in the Microsoft build. In source-build it failed in two ways: restore
could not find a portable-RID runtime pack (NU1102), and once scoped to the build's
non-portable RID the previous SDK rejected the project with NETSDK1203 ("Ahead-of-time
compilation is not supported for the target runtime identifier"). The root cause is
that every repo in the VMR builds against a previous SDK; in a stage 1 source-build
leg that SDK is the Microsoft portable SDK, whose bundled props do not list the build's
non-portable RID (e.g. centos.10-x64) in the ILCompiler/runtime-pack RID sets and whose
packs/ folder has no NativeAOT pack for that RID.

Teach the previous SDK about the source-built non-portable RID and unblock AOT publishing,
then ship the resulting aggregate in source-build. Fixes dotnet/source-build#5567.

Arcade SDK:
- TargetingPacks.BeforeCommonTargets.targets: in source-build, append the build's
  non-portable RID to the in-memory KnownILCompilerPack ILCompilerRuntimeIdentifiers
  (new), alongside the existing KnownRuntimePack and KnownCrossgen2Pack RID sets. Switch
  the appended value from $(NETCoreSdkRuntimeIdentifier) to $(TargetRid): in a stage 1 leg
  the bootstrap SDK is portable, so $(NETCoreSdkRuntimeIdentifier) is the portable RID and
  would not unblock publishing for the build's non-portable target RID.
- ProjectDefaults.targets: for source-build projects that publish with Native AOT, set
  StripSymbols=false so the produced binary keeps embedded DWARF (no separate symbol file
  or .gnu_debuglink). This is the AOT analog of source-build's KeepNativeSymbols=true and
  satisfies the source-build native-symbol validation. Scoped to PublishAot so non-AOT
  builds are unaffected, and gated on DotNetBuildSourceOnly so Microsoft builds still strip.
  Placed in .targets (imported after the project sets PublishAot) so the condition is known.

runtime:
- Microsoft.DotNet.ILCompiler.SingleEntry.targets: when source-build publishes for the
  non-portable target RID against a portable bootstrap SDK, the target OS derived from the
  RID (e.g. "centos") is not a valid ILC target OS. Map it to the portable base OS (e.g.
  "linux"), mirroring the existing non-portable SDK RID handling, without changing the
  host/target pack names the SDK already resolved.

aspnetcore:
- Remove the DotNetBuildSourceOnly != 'true' gates that disabled PublishAot for the three
  leaf tool projects and the aspnetcoretools aggregate, and include the aggregate in the
  source-build project set (eng/Build.props). Simplify the aggregate's RuntimeIdentifier(s)
  selection now that AOT runs in source-build too.

sdk:
- BundledDotnetTools.targets: bundle the Native AOT aspnetcoretools aggregate in source-build
  instead of the per-tool managed IL packages. Remove the three source-build-only per-tool
  entries and un-gate the RID-specific tool selection so the aggregate's non-portable RID
  package (e.g. aspnetcoretools.centos.10-x64) is selected.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings June 19, 2026 17:56
@dotnet-policy-service
dotnet-policy-service Bot requested review from a team June 19, 2026 17:57
@dotnet-policy-service
dotnet-policy-service Bot requested review from a team June 19, 2026 17:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables publishing and bundling the NativeAOT-compiled ASP.NET Core SDK CLI tools (via the aspnetcoretools aggregate) in VMR source-build legs by teaching the “previous SDK” about the build’s non-portable RID and adjusting NativeAOT/ILCompiler integration for that environment.

Changes:

  • Always bundle aspnetcoretools (including in source-build) and remove source-only fallback to individual RID-specific tool packages.
  • Enable NativeAOT publishing for aspnetcoretools and its component tools during source-build, and include the aggregate in aspnetcore’s build graph.
  • In source-build, extend the previous SDK’s known pack RID sets to include $(TargetRid) (including ILCompiler packs) and disable symbol stripping for PublishAot projects to satisfy source-build symbol validation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/sdk/src/Layout/redist/targets/BundledDotnetTools.targets Bundle aspnetcoretools in source-build and allow RID-specific package selection there.
src/runtime/src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targets Map non-portable source-build target OS to a portable OS token for ILC target OS derivation.
src/aspnetcore/src/Tools/NativeAot/aspnetcoretools/aspnetcoretools.csproj Include in source-build and always enable PublishAot for the aggregate tool.
src/aspnetcore/src/Tools/dotnet-user-secrets/src/dotnet-user-secrets.csproj Enable PublishAot for source-build (remove gating).
src/aspnetcore/src/Tools/dotnet-user-jwts/src/dotnet-user-jwts.csproj Enable PublishAot for source-build (remove gating).
src/aspnetcore/src/Tools/dotnet-dev-certs/src/dotnet-dev-certs.csproj Enable PublishAot for source-build (remove gating).
src/aspnetcore/eng/Build.props Build the NativeAOT aggregate tool project during source-build.
src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/TargetingPacks.BeforeCommonTargets.targets Append $(TargetRid) to Known* pack RID lists in source-build, including ILCompiler packs.
src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/ProjectDefaults.targets Disable NativeAOT symbol stripping in source-build to keep embedded DWARF in ELF outputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mthalman
mthalman requested a review from a team June 19, 2026 20:13
@mthalman

Copy link
Copy Markdown
Member Author

Code reviewers - PTAL

@akoeplinger

Copy link
Copy Markdown
Member

LGTM apart from one comment

Addresses review feedback: the previous fix placed VMR-specific properties (DotNetBuildSourceOnly/TargetRid) in Microsoft.DotNet.ILCompiler.SingleEntry.targets, which ships in the ILCompiler NuGet package and runs on end-user builds.

Replace that with a general ILC robustness fix using only ILC-intrinsic signals: when the target OS token derived from the RuntimeIdentifier is version-qualified (contains '.', e.g. 'centos.10' from 'centos.10-x64') and the RID is not the running SDK's own non-portable RID, map it to the SDK-reported portable base OS (e.g. 'linux'). Valid base OS tokens never contain a '.', so this reliably identifies a non-portable target RID published against a portable SDK. The SDK still resolves the host/target packs by full RID; only the ILC target OS needs normalizing.

Co-authored-by: Copilot <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Address PR review feedback on the Native AOT StripSymbols override in
ProjectDefaults.targets:

- Derive StripSymbols from the KeepNativeSymbols property instead of
  re-deriving the source-build policy from DotNetBuildSourceOnly, so a
  single overridable property controls native-symbol stripping.
- Default KeepNativeSymbols to true for source-build here so it is in
  scope for repos (e.g. aspnetcore) that publish AOT SDK tools; it is
  otherwise only defaulted within the runtime build.
- Drop the PublishAot scoping; StripSymbols is inert for non-AOT
  projects, so setting it unconditionally is harmless.
- Correct the comment: shipping native binaries have their symbols
  stripped and archived by the distro packaging process, not shipped
  with embedded symbols; remove the issue link.

Co-authored-by: Copilot <[email protected]>
@mthalman
mthalman requested a review from jkotas June 29, 2026 14:56
@mthalman
mthalman enabled auto-merge (squash) June 29, 2026 17:23
@mthalman
mthalman merged commit ccf0d06 into dotnet:main Jun 30, 2026
11 checks passed
@mthalman
mthalman deleted the dev/mthalman/aot-sdk-tools-source-build branch June 30, 2026 09:35
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.

Enable AOT-compiled SDK tools when the SDK is built via source-build

5 participants