You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
GenerateBindings and AddBindingsToCompile are not run for a project build happening under _ResolveAssemblies causing incremental builds to break #9007
Now that this build is happening with _ComputeFilesToPublishForRuntimeIdentifiers being true, the Microsoft.Android.Sdk.BuildOrder.targets isn't imported. Then, CompileDependsOn is missing the GenerateBindings and AddBindingsToCompile targets. This causes _GenerateCompileDependencyCache to not include some files, breaking things VERY badly.
In the above binlog, _GenerateCompileDependencyCache of build 351 is run first, then that of build 88 which overwritten Uno.UI.BindingHelper.Android.netcoremobile.csproj.CoreCompileInputs.cache causing Uno.UI.BindingHelper.Android.netcoremobile to be rebuilt unnecessarily, which then causes almost everything to be rebuilt.
Steps to Reproduce
Binlog shows it all I think. If more info is needed, let me know.
Now that I think this over AddBinginsToCompile should only be run on the outer builds. Since the source code will not change (like all the other code). So I would expect to see it run before all the abi specific inner builds run. This is all assuming its an android build of course. I guess it gets more complicated when we have multiple platforms as the outer build, then a platform specific inner build then abi specific inner inner builds.
I'm not even sure we have a unit test to cover that as integrating single projects like maui into our repo testing framework has proved very problematic since maui is always being updated and changing.
Generally, the Android inner build only runs <ILLink/> and the AOT compiler. I don't think it even would run the C# compiler at all? Doesn't seem like AddBindingsToCompile should run in an inner build?
Ok, so maybe we need $(_ComputeFilesToPublishForRuntimeIdentifiers) to always be unset during ResolveProjectReferences. This could go wrong depending on what order projects are built.
There is a RemoveProperties argument for the <MSBuild/> task:
Do you have an idea of what project/solution structure would cause this to break? I think next step would be for us to write a test to reproduce the problem.
This comment was generated by Claude (an AI assistant), from a repro it built and ran locally on my machine.
Here is a minimal repro for this, with public bits only: .NET SDK 10.0.403, Microsoft.Android.Sdk.Darwin 36.1.118,
macOS arm64.
Setup:dotnet new android (App), Release with RuntimeIdentifier=android-arm64, AndroidLinkTool=r8 and AndroidPackageFormat=apk, plus one ProjectReference. Either of these is enough:
dotnet new androidlib with no changes (no Java, no bindings), or
dotnet new android-bindinglib with one <AndroidLibrary Include="tiny.aar" />.
Steps:dotnet build -c Release three times, changing nothing.
Expected: builds 2 and 3 compile nothing and do not package the app again.
Actual: every build recompiles the library (its .dll gets a new timestamp) and the app runs ResolveLibraryProjectImports and BuildArchive again:
build
library compiled
app imports re-run
app packaged
1
yes
yes
yes
2 (no change)
yes
yes
yes
3 (no change)
yes
yes
yes
Why (as described above): _ResolveAssemblies builds the app again with _ComputeFilesToPublishForRuntimeIdentifiers=true, SkipCompilerExecution=true and the _Outer* properties as global properties
(Microsoft.Android.Sdk.AssemblyResolution.targets#L82-L108).
That inner build's ResolveProjectReferences builds the library with those global properties too, so the library is
evaluated without Microsoft.Android.Sdk.BuildOrder.targets
(Microsoft.Android.Sdk.After.targets#L15).
Its _GenerateCompileDependencyCache then hashes a different set of inputs and rewrites the shared obj/.../<Lib>.csproj.CoreCompileInputs.cache. Comparing the two Hash task inputs in one build: the inner
evaluation lists the same DefineConstants in a different order (the __XAMARIN_ANDROID_v1_0__/__MOBILE__/ __ANDROID_<n>__ defines move relative to NET*/ANDROID*; both libraries; enough on its own to change the hash),
and in the binding library it also lacks the generated binding sources (obj/.../generated/src/*.cs). On the next build
the outer evaluation finds the cache newer than the .dll and compiles again, and so on forever.
Knock-on effects: because the app's library imports re-run on every build, every build also hits #12965 (the
libraries' proguard.txt rules are dropped from libraryprojectimports.cache; fixed by #13061, not in .NET 10) and,
every other build, #11543 (the APK loses its Java resources; fixed by #11552, not in .NET 10). With the binding
library above, a plain no-change dotnet build -c Release gives an APK without META-INF/services/... on every
second build.
Workaround: keep the inner build's properties off the app's project references. Undefining only _ComputeFilesToPublishForRuntimeIdentifiers stops the recompile (a no-change build drops from about 16 s to 7 s).
Undefining all of them lets the inner build reuse the outer build's results (about 1.6 s):
A fix in the SDK could do the same: have the inner build remove its private properties for project references
(_GlobalPropertiesToRemoveFromProjectReferences, as suggested above, or BuildProjectReferences=false so the inner
build only asks references for their outputs). main (checked 2026-11) still passes these properties through, and the
nested-build changes in #13202 add more of them.
App.csproj for the repro (with dotnet new androidlib -n Lib next to it)
To see it: dotnet build -c Release twice, then compare the timestamp of Lib/obj/Release/net10.0-android/Lib.dll before and after the second build, or look for Building target "CoreCompile" completely for Lib.csproj in a -v:diag log: Input file "obj/Release/net10.0-android/Lib.csproj.CoreCompileInputs.cache" is newer than output file ….
Activity
dellis1972 commentedon Jun 6, 2024
@Youssef1313 this all happens within Visual Studio I assume?
Do you get the same issue from the command line?
Youssef1313 commentedon Jun 6, 2024
My testing was from command-line actually. But I assume it's an issue in VS as well.
dellis1972 commentedon Jun 7, 2024
Now that I think this over
AddBinginsToCompileshould only be run on the outer builds. Since the source code will not change (like all the other code). So I would expect to see it run before all the abi specific inner builds run. This is all assuming its an android build of course. I guess it gets more complicated when we have multiple platforms as the outer build, then a platform specific inner build then abi specific inner inner builds.I'm not even sure we have a unit test to cover that as integrating single projects like maui into our repo testing framework has proved very problematic since maui is always being updated and changing.
@jonathanpeppers do you have any thoughts on this one?
Youssef1313 commentedon Jun 7, 2024
I'm not very much following on "why".
To me, not running it will simply cause
_GenerateCompileDependencyCacheto not have all the.csinputs, which then causes a lot of trouble.jonathanpeppers commentedon Jun 7, 2024
Generally, the Android inner build only runs
<ILLink/>and the AOT compiler. I don't think it even would run the C# compiler at all? Doesn't seem likeAddBindingsToCompileshould run in an inner build?See this for some details:
I've not had a chance to look into this one to see what might be going wrong here. I've been focusing on MAUI, unfortunately.
Youssef1313 commentedon Jun 7, 2024
Well, as part of the build happening under
_ResolveAssembliesthere isResolveProjectReferenceswhich then invokesMSBuildhttps://github.com/dotnet/msbuild/blob/98c28cc33dc4671e6d502e41c80c610b54085139/src/Tasks/Microsoft.Common.CurrentVersion.targets#L2133-L2145
jonathanpeppers commentedon Jun 7, 2024
Ok, so maybe we need
$(_ComputeFilesToPublishForRuntimeIdentifiers)to always be unset duringResolveProjectReferences. This could go wrong depending on what order projects are built.There is a
RemovePropertiesargument for the<MSBuild/>task:Looking at:
https://github.com/dotnet/msbuild/blob/98c28cc33dc4671e6d502e41c80c610b54085139/src/Tasks/Microsoft.Common.CurrentVersion.targets#L2123
I guess we could try
$(_GlobalPropertiesToRemoveFromProjectReferences)? It's private...Youssef1313 commentedon Jun 7, 2024
To me it's quite scary to rely on private properties of MSBuild, but it could work (and, well, I sometimes rely on MSBuild internals myself 😄).
jonathanpeppers commentedon Jun 7, 2024
@Youssef1313 can you test if that works around your problem for now?
This is used in a few places:
Youssef1313 commentedon Jun 7, 2024
Sure. I'll test it and let you know.
Youssef1313 commentedon Jun 10, 2024
@jonathanpeppers Thanks. I tested it and it works. However, is it something that can be done on your side instead of consumers having to deal with it?
jonathanpeppers commentedon Jun 18, 2024
Do you have an idea of what project/solution structure would cause this to break? I think next step would be for us to write a test to reproduce the problem.
Youssef1313 commentedon Jun 18, 2024
@jonathanpeppers Unfortunately, I have no minimal repro. But maybe the binlog in the issue could help crafting a repro?
AdamEssenmacher commentedon Nov 4, 2026
Here is a minimal repro for this, with public bits only: .NET SDK 10.0.403, Microsoft.Android.Sdk.Darwin 36.1.118,
macOS arm64.
Setup:
dotnet new android(App), Release withRuntimeIdentifier=android-arm64,AndroidLinkTool=r8andAndroidPackageFormat=apk, plus oneProjectReference. Either of these is enough:dotnet new androidlibwith no changes (no Java, no bindings), ordotnet new android-bindinglibwith one<AndroidLibrary Include="tiny.aar" />.Steps:
dotnet build -c Releasethree times, changing nothing.Expected: builds 2 and 3 compile nothing and do not package the app again.
Actual: every build recompiles the library (its
.dllgets a new timestamp) and the app runsResolveLibraryProjectImportsandBuildArchiveagain:Why (as described above):
_ResolveAssembliesbuilds the app again with_ComputeFilesToPublishForRuntimeIdentifiers=true,SkipCompilerExecution=trueand the_Outer*properties as global properties(Microsoft.Android.Sdk.AssemblyResolution.targets#L82-L108).
That inner build's
ResolveProjectReferencesbuilds the library with those global properties too, so the library isevaluated without
Microsoft.Android.Sdk.BuildOrder.targets(Microsoft.Android.Sdk.After.targets#L15).
Its
_GenerateCompileDependencyCachethen hashes a different set of inputs and rewrites the sharedobj/.../<Lib>.csproj.CoreCompileInputs.cache. Comparing the twoHashtask inputs in one build: the innerevaluation lists the same
DefineConstantsin a different order (the__XAMARIN_ANDROID_v1_0__/__MOBILE__/__ANDROID_<n>__defines move relative toNET*/ANDROID*; both libraries; enough on its own to change the hash),and in the binding library it also lacks the generated binding sources (
obj/.../generated/src/*.cs). On the next buildthe outer evaluation finds the cache newer than the
.dlland compiles again, and so on forever.Knock-on effects: because the app's library imports re-run on every build, every build also hits #12965 (the
libraries'
proguard.txtrules are dropped fromlibraryprojectimports.cache; fixed by #13061, not in .NET 10) and,every other build, #11543 (the APK loses its Java resources; fixed by #11552, not in .NET 10). With the binding
library above, a plain no-change
dotnet build -c Releasegives an APK withoutMETA-INF/services/...on everysecond build.
Workaround: keep the inner build's properties off the app's project references. Undefining only
_ComputeFilesToPublishForRuntimeIdentifiersstops the recompile (a no-change build drops from about 16 s to 7 s).Undefining all of them lets the inner build reuse the outer build's results (about 1.6 s):
A fix in the SDK could do the same: have the inner build remove its private properties for project references
(
_GlobalPropertiesToRemoveFromProjectReferences, as suggested above, orBuildProjectReferences=falseso the innerbuild only asks references for their outputs).
main(checked 2026-11) still passes these properties through, and thenested-build changes in #13202 add more of them.
App.csproj for the repro (with
dotnet new androidlib -n Libnext to it)To see it:
dotnet build -c Releasetwice, then compare the timestamp ofLib/obj/Release/net10.0-android/Lib.dllbefore and after the second build, or look forBuilding target "CoreCompile" completelyforLib.csprojin a-v:diaglog: Input file "obj/Release/net10.0-android/Lib.csproj.CoreCompileInputs.cache" is newer than output file ….