Skip to content

[Build] Add Inputs/Outputs to _GenerateCompressedAssembliesNativeSourceFiles#11188

Closed
jonathanpeppers wants to merge 4 commits intomainfrom
jonathanpeppers/compressed-assemblies-incremental
Closed

[Build] Add Inputs/Outputs to _GenerateCompressedAssembliesNativeSourceFiles#11188
jonathanpeppers wants to merge 4 commits intomainfrom
jonathanpeppers/compressed-assemblies-incremental

Conversation

@jonathanpeppers
Copy link
Copy Markdown
Member

Description

_GenerateCompressedAssembliesNativeSourceFiles took 147ms on an
incremental build because it had no Inputs/Outputs — it ran every
time regardless of whether any assemblies changed.

This PR adds:

  • Inputs: @(_ResolvedUserAssemblies);@(_ResolvedFrameworkAssemblies);$(_AndroidBuildPropertiesCache)
  • Outputs: @(_CompressedAssembliesAssemblySource) (the .ll files,
    already populated by _PrepareNativeAssemblySourceItems)

This should prevent the target from running on a build with no changes.

Also updates BasicApplicationRepetitiveBuild to assert the target is
skipped on a no-change rebuild.

jonathanpeppers and others added 2 commits April 22, 2026 16:12
…ceFiles

Add Inputs/Outputs to the _GenerateCompressedAssembliesNativeSourceFiles
target so it is skipped on incremental builds when no assemblies have
changed. This saves ~143ms on every no-change rebuild.

- Inputs: @(_ResolvedUserAssemblies);@(_ResolvedFrameworkAssemblies)
- Outputs: @(_CompressedAssembliesAssemblySource) (the .ll files)

Also update BasicApplicationRepetitiveBuild to assert the target is
skipped on a no-change rebuild.

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

Include $(_AndroidBuildPropertiesCache) (build.props) so that changes
to build properties like Debug or EnableCompression also trigger a rebuild.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings April 22, 2026 21:15
The task uses Files.CopyIfStreamChanged which preserves the old
timestamp when content is unchanged. Without Touch, MSBuild would
always see inputs newer than outputs and re-run the target.

Co-authored-by: Copilot <[email protected]>
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

Adds MSBuild incremental build semantics to _GenerateCompressedAssembliesNativeSourceFiles so it can be skipped on no-change rebuilds, and updates an incremental build test to assert the skip behavior.

Changes:

  • Add Inputs/Outputs to _GenerateCompressedAssembliesNativeSourceFiles in Xamarin.Android.Common.targets.
  • Update BasicApplicationRepetitiveBuild to assert _GenerateCompressedAssembliesNativeSourceFiles is skipped on a no-change rebuild.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets Adds MSBuild incremental inputs/outputs to avoid re-running compressed-assemblies native source generation on unchanged builds.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs Adds an assertion that the target is skipped on the second build.

Comment thread src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Comment thread src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Assert.IsTrue (
b.Output.IsTargetSkipped ("_Sign"),
"the _Sign target should not run");
b.Output.AssertTargetIsSkipped ("_GenerateCompressedAssembliesNativeSourceFiles");
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

AssertTargetIsSkipped ("_GenerateCompressedAssembliesNativeSourceFiles") is unconditional, but _GenerateCompressedAssembliesNativeSourceFiles is conditioned out when runtime == AndroidRuntime.NativeAOT. If the NativeAOT build path doesn’t invoke the target (and therefore doesn’t emit a “skipped” message), this assertion will fail. Consider guarding the assertion to non-NativeAOT runtimes, or pass defaultIfNotUsed: true for the NativeAOT case.

Suggested change
b.Output.AssertTargetIsSkipped ("_GenerateCompressedAssembliesNativeSourceFiles");
if (runtime != AndroidRuntime.NativeAOT) {
b.Output.AssertTargetIsSkipped ("_GenerateCompressedAssembliesNativeSourceFiles");
}

Copilot uses AI. Check for mistakes.
The compressed assemblies task uses EnableCompression to change its
output, so toggling this property must invalidate build.props to
trigger a rebuild.

Co-authored-by: Copilot <[email protected]>
@jonathanpeppers jonathanpeppers marked this pull request as draft April 23, 2026 13:39
@jonathanpeppers
Copy link
Copy Markdown
Member Author

Ok, this breaks things, due to:

Root cause: _GenerateCompressedAssembliesNativeSourceFiles calls
RegisterTaskObjectAssemblyLocal to pass compression metadata to
CollectAssemblyFilesForArchive. When Inputs/Outputs skips the target
on incremental builds, that registration never happens.

CollectAssemblyFilesForArchive then throws:
  "Assembly compression info not found for key '{key}'"

This only affects Release builds with compression enabled (Debug
builds skip registration entirely via the early-exit on line 42).

Fix: The task needs to write the compression info to a file (like a
.cache file) instead of using RegisterTaskObjectAssemblyLocal. Then
CollectAssemblyFilesForArchive reads from the file. This way the
target can be skipped and the data persists across builds.

I would say we should finish trimmable type map, which removes RegisterTaskObject() usage.

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