Skip full Build for AOT publish, use Compile instead#54515
Conversation
When publishing with PublishAot=true, the implicit Build step was producing a full self-contained managed deployment (apphost, DLLs, deps.json, runtimeconfig, runtime pack files) in the output directory. This output is completely unused by the AOT pipeline, which reads from @(IntermediateAssembly) in obj\, not from bin\ output. This change introduces _PublishAotBuildAlternative that runs Compile (plus resource and satellite assembly targets) instead of full Build for AOT publish. This eliminates the confusing managed artifacts from the output directory while preserving all AOT publish functionality. The target list for AOT publish is: - BuildOnlySettings: configures build-time settings - PrepareForBuild: creates output directories - PrepareResources: compiles .resx to .resources files - Compile: produces IL assembly in obj\ (includes ResolveReferences) - CreateSatelliteAssemblies: generates culture-specific resource DLLs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| Condition="'$(NoBuild)' != 'true' and '$(PublishAot)' != 'true'" | ||
| DependsOnTargets="Build;$(_CorePublishTargets)" /> | ||
|
|
||
| <Target Name="_PublishAotBuildAlternative" | ||
| Condition="'$(NoBuild)' != 'true' and '$(PublishAot)' == 'true'" | ||
| DependsOnTargets="$(_PublishAotBuildAlternativeDependsOn)" /> |
There was a problem hiding this comment.
Would this logic/split be the same for apps that are merely trimmed too? They are similarly platform-specific and just need the primary output dlls.
There was a problem hiding this comment.
copilot agrees with you but thinks we should start small: I'd recommend keeping this PR focused on AOT only. The same pattern applies to PublishTrimmed, PublishReadyToRun, and PublishSingleFile, but those have broader usage and more interaction surface. Better to validate AOT first, then extend in a follow-up PR.
It seems to be worried about the impact changing the others would have.
There was a problem hiding this comment.
Pull request overview
This PR changes Native AOT publish so it compiles the intermediate IL needed by the AOT pipeline without running the full Build target, avoiding unused managed self-contained artifacts in bin output.
Changes:
- Adds an AOT-specific publish build alternative in
Microsoft.NET.Publish.targets. - Routes
PublishAot=truepublishes throughCompile/resource targets instead of fullBuild. - Updates and adds Native AOT publish tests for clean output and project-reference publishing.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets |
Adds _PublishAotBuildAlternative and excludes AOT publish from the normal full-build path. |
test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs |
Updates property-recording hooks for skipped Build and adds Native AOT publish regression tests. |
| @(IntermediateAssembly) in obj\, not from bin\ output. Skipping Build avoids producing | ||
| unnecessary self-contained managed output (apphost, deps.json, runtimeconfig, runtime | ||
| pack files) in the output directory that would confuse users and automation. --> | ||
| <_BeforePublishAotBuildTargets Condition="'$(PublishAot)' == 'true'"> |
There was a problem hiding this comment.
There's a part of me that thinks that we could make this even better if we didn't call these targets on this project instance - instead, if we could set up targets that called this chain on 'this project instance with RuntimeIdentifier' removed, you'd get almost all of the way to an 'agnostic' build with 'platform-specific' publish steps.
…mentation - Add UseAotOptimizedPublish property (default true for PublishAot) as opt-out to restore old Build behavior during AOT publish - Improve test to verify runtime pack files (System.Private.CoreLib.dll, coreclr.dll) are not present in build output directory - Add publish-build-optimization.md documenting the breaking change, all publish modes, opt-out mechanism, and future work Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When publishing with PublishAot=true, the implicit Build step was producing a full self-contained managed deployment (apphost, DLLs, deps.json, runtimeconfig, runtime pack files) in the output directory. This output is completely unused by the AOT pipeline, which reads from @(IntermediateAssembly) in obj, not from bin\ output.
This change introduces _PublishAotBuildAlternative that runs Compile (plus resource and satellite assembly targets) instead of full Build for AOT publish. This eliminates the confusing managed artifacts from the output directory while preserving all AOT publish functionality.
The target list for AOT publish is: