[build] Pass class files directly to D8 and R8 - #12438
Conversation
Avoid creating an intermediate classes.zip after javac. D8 and R8 accept individual .class inputs through their response files, eliminating redundant archive I/O. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Android build pipeline to avoid generating an intermediate classes.zip for application builds, instead passing compiled .class files directly into D8/R8 via the existing response-file mechanism. This aligns the build tasks with D8/R8 supported inputs and reduces unnecessary I/O during javac.
Changes:
- Stop producing
obj/.../android/bin/classes.zipfor app builds; use.classfiles from$(_AndroidIntermediateJavaClassDirectory)as D8/R8 program inputs. - Update
_CompileToDalvikincremental inputs to use the Java compile stamp ($(_AndroidCompileJavaStampFile)) instead ofclasses.zip. - Adjust D8 task API/response-file generation and update D8 unit tests accordingly.
Show a summary per file
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Xamarin.Android.D8.targets | Passes @(_JavaClassFile) (compiled .class files) directly to D8/R8 instead of classes.zip. |
| src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | Removes the classes.zip intermediate property and switches dex incremental input to the Java compile stamp. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/D8Tests.cs | Extends the D8 response-file unit test to cover .class inputs. |
| src/Xamarin.Android.Build.Tasks/Tasks/D8.cs | Replaces ClassesZip with ClassFiles and emits .class paths as program inputs in the response file. |
| src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Javac.targets | Stops deleting/passing classes.zip for app Java compilation, leaving binding JAR generation intact elsewhere. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
Update BuildIncrementingClassName to validate the class output directory now that app builds no longer create classes.zip. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| Outputs="$(_AndroidCompileJavaStampFile)"> | ||
|
|
||
| <!-- remove existing <Javac /> outputs, since *.class files and classes.zip could contain old files --> | ||
| <!-- remove existing <Javac /> outputs, since *.class files could contain old files --> |
There was a problem hiding this comment.
The <Javac/> task still has the ClassesZip property and code to create the classes.zip, can we remove that, too?
There was a problem hiding this comment.
Done in 3d7d113. Javac no longer has a ClassesZip property or archive-writing code. _CompileBindingJava now creates its required binding JAR separately with MSBuild’s ZipDirectory task.
There was a problem hiding this comment.
Follow-up in ceb8a43: class-parse app builds now avoid the binding JAR as well. Their bound .class files flow directly to class-parse, javac, and D8/R8. JAR creation remains only for library/AAR output and legacy jar2xml.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pass bound Java class files directly to class-parse, javac, and D8/R8. Retain JAR creation for library packaging and legacy jar2xml builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/review |
|
✅ Android PR Reviewer completed successfully!
|
There was a problem hiding this comment.
The loose .class flow is coherently wired through javac, class-parse, and D8/R8, and retaining the JAR for binding projects and jar2xml preserves the required archive consumers. The added app-build assertion must first use an actual bound Java source; as written, it cannot catch regressions in the new _JavaBindingClassFile path.
CI build 1560618 is currently red and still in progress: both macOS package-test APK lanes are failing while several Windows, Linux, and emulator lanes remain active. I could not verify that those failures are related to this change, so this review does not attribute them to the PR.
Generated by Android PR Reviewer for #12438 · gpt56 · 400.8 AIC · ⌖ 8.95 AIC · ⊞ 25.7K
Comment /review to run again
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
left a comment
There was a problem hiding this comment.
I reran to see if that would help, but I think this is broken on APK tests:
EXEC : warning : [options] system modules path not set in conjunction with -source 17 [/Users/runner/work/1/s/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.NET.csproj]
/Users/runner/work/1/s/bin/Release/dotnet/packs/Microsoft.Android.Sdk.Darwin/37.0.0-ci.pr.gh12438.0/tools/Xamarin.Android.Bindings.ClassParse.targets(51,5): error MSB6006: "dotnet" exited with code 1. [/Users/runner/work/1/s/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj]
/Users/runner/work/1/s/bin/Release/dotnet/packs/Microsoft.Android.Sdk.Darwin/37.0.0-ci.pr.gh12438.0/tools/Xamarin.Android.Bindings.ClassParse.targets(51,5): error XACLP0000: class-parse: Unable to read file 'obj/Debug/net11.0-android/binding/bin/classes/net/dot/android/test/Example%241.class': Could not find file '/Users/runner/work/1/s/tests/Mono.Android-Tests/Mono.Android-Tests/obj/Debug/net11.0-android/binding/bin/classes/net/dot/android/test/Example%241.class'. [/Users/runner/work/1/s/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj]
/Users/runner/work/1/s/bin/Release/dotnet/packs/Microsoft.Android.Sdk.Darwin/37.0.0-ci.pr.gh12438.0/tools/Xamarin.Android.Bindings.ClassParse.targets(51,5): error XACLP0000: class-parse: Unable to read file 'obj/Debug/net11.0-android/binding/bin/classes/net/dot/android/test/InterfaceMarshalling%241.class': Could not find file '/Users/runner/work/1/s/tests/Mono.Android-Tests/Mono.Android-Tests/obj/Debug/net11.0-android/binding/bin/classes/net/dot/android/test/InterfaceMarshalling%241.class'. [/Users/runner/work/1/s/tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj]
Build failed with exit code: 1.
|
If we kept I didn't realize it complicated some of the binding code paths. |
Related: #10958
Summary
obj/.../android/bin/classes.zipafterjavacfor app builds.classfiles directly toclass-parse,javac, and D8/R8Javactaskjar2xmlD8 and R8 both accept individual
.classfiles as program inputs. The Windows command-line limit was originally reported as Xamarin Bugzilla #59651. PR #888 initially addressed it by passing the class directory todx.jar; PR #911 then introducedclasses.zipbecausej8.jaralso needed to consume the classes without exceeding the command-line limit. D8/R8 response files make that workaround unnecessary.Application projects containing bound
AndroidJavaSourcefiles also avoid an intermediate binding JAR:class-parseconsumes the loose binding classes directly, the regular Java compilation uses their directory as a classpath entry, and D8/R8 receives the class files as program inputs. Library projects still create a JAR because it is packaged into their AAR; legacyjar2xmlalso continues to require a JAR.Performance
Balanced 5+5 clean MAUI Debug Android builds using
--no-restore:The
Javactask mean fell from 4.235s to 2.757s for LLVM-IR and from 6.890s to 3.278s for trimmable because it no longer packages the class output.The final loose binding-class implementation was also compared directly with the earlier implementation that still created a binding JAR in application projects:
Binding
Javactime was unchanged, while passing the class file directly toclass-parsewas 106–120ms faster on average. No application build in the loose-class sample produced a binding JAR.Validation
D8Tests: 2 passedclasses.zipor an application binding JAR