[Build] Split _GenerateJavaStubs into independent sub-targets for incremental build performance#11056
Draft
davidnguyen-tech wants to merge 6 commits intodotnet:mainfrom
Draft
Conversation
When _CompileNativeAssemblySources runs, it recompiles ALL .ll files even if only some have changed. Add a per-file timestamp check in RunAssembler() so that if the output .o is newer than the input .ll, that file is skipped. This complements the upcoming target split by ensuring unchanged type map files are not recompiled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… MSBuild property Add [Output] JniAddNativeMethodRegistrationAttributePresent to GenerateTypeMappings and a matching input property on GenerateNativeApplicationConfigSources. This decouples the cross-target static state so the value can be persisted to a cache file and read back when _GenerateTypeMappings is skipped on incremental builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add four input gatherer targets that compute narrowed input sets for the upcoming sub-targets of _GenerateJavaStubs: - _GetGenerateJavaCallableWrappersInputs: .jlo.xml sidecar files - _GetGenerateJavaStubsCoreInputs: assembly hash, manifest, environment - _GetGenerateTypeMappingsInputs: .typemap.xml sidecar files - _GetGenerateAndroidManifestInputs: manifest template, environment Each sub-target has narrower inputs than the monolithic target, enabling MSBuild to skip unchanged sub-tasks on incremental builds. The core inputs include manifest and environment files to ensure NativeCodeGenState is always registered when downstream targets need it. Also wire the JNI registration attribute cache file to GenerateNativeApplicationConfigSources via ReadLinesFromFile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split the monolithic _GenerateJavaStubs target into four independent sub-targets, each with their own Inputs/Outputs for incrementality: - _GenerateJavaCallableWrappers: JCW generation + ACW map - _GenerateJavaStubsCore: code gen state + marshal method rewriting - _GenerateTypeMappings: type map .ll file generation - _GenerateAndroidManifest: manifest + provider source generation The original _GenerateJavaStubs target is preserved as a no-op wrapper with DependsOnTargets for backward compatibility. Sub-targets explicitly depend on _GetGenerateJavaStubsInputs to ensure @(_EnvironmentFiles) is populated. The JNI registration attribute flag is persisted to a cache file for downstream targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add matching stub sub-targets in the Trimmable typemap targets file to maintain consistency with the LlvmIr path. All sub-targets are stubs that skip immediately, matching the existing behavior where _GenerateJavaStubs was a single stub target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the existing GenerateJavaStubsAndAssembly test to verify the new sub-targets follow the same incrementality rules. Add a new GenerateJavaStubsSubTargetIncrementality test verifying all sub-targets skip on no-change rebuilds. Update skip assertions to check _GenerateJavaStubsCore instead of the wrapper _GenerateJavaStubs (which has no Inputs/Outputs and never reports as skipped). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Split the monolithic
_GenerateJavaStubstarget into four independent sub-targets, each with their own Inputs/Outputs for MSBuild incrementality:_GenerateJavaCallableWrappers: JCW generation + ACW map (reads .jlo.xml sidecar files)_GenerateJavaStubsCore: Code gen state production + marshal method rewriting_GenerateTypeMappings: Type map .ll file generation (highest-value split — 2.21s on CoreCLR)_GenerateAndroidManifest: Manifest + provider source generationThe original
_GenerateJavaStubstarget is preserved as a no-op wrapper withDependsOnTargetsfor backward compatibility.Motivation
In a MAUI Android CoreCLR incremental build (13.6s total),
_GenerateJavaStubstakes ~3.24s and is the single largest bottleneck. It contains 8 sequential tasks gated by a single Inputs/Outputs pair. When the assembly changes (any C# edit), all 8 tasks execute even if only one has work to do.This triggers a cascade: GenerateTypeMappings regenerates .ll files →
_CompileNativeAssemblySourcesrecompiles them (2.85s). Total cascade cost: ~5.5s of unnecessary work.Changes
Per-file up-to-date check (
CompileNativeAssembly.cs)Added timestamp check so unchanged .ll → .o compilations are skipped, even when the target runs.
C# task changes (
GenerateTypeMappings.cs,GenerateNativeApplicationConfigSources.cs)Externalized
NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresentas an MSBuild[Output]property, persisted to a cache file. This decouples cross-target static state for incremental scenarios.MSBuild target changes
Xamarin.Android.Common.targets: Added 4 input gatherer sub-targets with narrowed inputs, wired JNI registration cache to downstream targetMicrosoft.Android.Sdk.TypeMap.LlvmIr.targets: Split monolithic target into 4 sub-targets with independent stamp filesMicrosoft.Android.Sdk.TypeMap.Trimmable.targets: Added matching stub sub-targetsTests (
IncrementalBuildTest.cs,AndroidUpdateResourcesTest.cs)GenerateJavaStubsAndAssemblytest to cover sub-targetsGenerateJavaStubsSubTargetIncrementalitytest verifying sub-targets skip independently_GenerateJavaStubsCoreinstead of wrapper target