diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs index 86ffb5bf8a4..f96dc8783cd 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs @@ -102,6 +102,81 @@ public class Foo { } } + [Test] + public void JniRemappingCountsSurviveIncrementalBuild () + { + const AndroidRuntime runtime = AndroidRuntime.CoreCLR; + const bool isRelease = true; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + OtherBuildItems = { + new AndroidItem._AndroidRemapMembers ("Remap.xml") { + Encoding = Encoding.UTF8, + TextContent = () => """ + + + + +""", + }, + }, + }; + proj.SetRuntime (runtime); + + using (var b = CreateApkBuilder ()) { + Assert.IsTrue (b.Build (proj), "first build failed"); + AssertJniRemappingCounts (proj, b, expectedTypeCount: 1, expectedMethodCount: 1); + var remapSourceTimestamps = GetJniRemappingSourceTimestamps (proj, b); + + proj.MainActivity += Environment.NewLine + "// Force an incremental C# rebuild."; + proj.Touch ("MainActivity.cs"); + Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "second build failed"); + AssertJniRemappingCounts (proj, b, expectedTypeCount: 1, expectedMethodCount: 1); + AssertJniRemappingSourceTimestamps (remapSourceTimestamps); + } + } + + void AssertJniRemappingCounts (XamarinAndroidApplicationProject proj, ProjectBuilder builder, uint expectedTypeCount, uint expectedMethodCount) + { + string objDirPath = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath); + var envFiles = EnvironmentHelper.GatherEnvironmentFiles (objDirPath, "arm64-v8a;x86_64", required: true, runtime: AndroidRuntime.CoreCLR); + var appConfig = (EnvironmentHelper.ApplicationConfig_CoreCLR) EnvironmentHelper.ReadApplicationConfig (envFiles, AndroidRuntime.CoreCLR); + Assert.AreEqual (expectedTypeCount, appConfig.jni_remapping_replacement_type_count, "jni_remapping_replacement_type_count should be preserved."); + Assert.AreEqual (expectedMethodCount, appConfig.jni_remapping_replacement_method_index_entry_count, "jni_remapping_replacement_method_index_entry_count should be preserved."); + } + + Dictionary GetJniRemappingSourceTimestamps (XamarinAndroidApplicationProject proj, ProjectBuilder builder) + { + string objDirPath = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "android"); + var timestamps = new Dictionary (StringComparer.Ordinal); + foreach (string abi in new [] { "arm64-v8a", "x86_64" }) { + string path = Path.Combine (objDirPath, $"jni_remap.{abi}.ll"); + FileAssert.Exists (path); + timestamps.Add (path, File.GetLastWriteTimeUtc (path)); + } + return timestamps; + } + + void AssertJniRemappingSourceTimestamps (Dictionary expectedTimestamps) + { + foreach (var expectedTimestamp in expectedTimestamps) { + Assert.AreEqual ( + expectedTimestamp.Value, + File.GetLastWriteTimeUtc (expectedTimestamp.Key), + $"{expectedTimestamp.Key} should not be touched when regenerated with unchanged contents." + ); + } + } + [Test] public void CheckNothingIsDeletedByIncrementalClean ([Values] bool enableMultiDex, [Values] AndroidRuntime runtime) { diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 539ee59f193..fd444a89512 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1646,21 +1646,22 @@ because xbuild doesn't support framework reference assemblies. <_GenerateAndroidRemapNativeCodeDependsOn> _ConvertAndroidMamMappingFileToXml; _CollectAndroidRemapMembers; - _PrepareAndroidRemapNativeAssemblySources + _PrepareAndroidRemapNativeAssemblySources; + _GetGeneratePackageManagerJavaInputs + Inputs="@(_GeneratePackageManagerJavaInputs);$(_XARemapMembersFilePath)" + Outputs="$(_AndroidStampDirectory)_GenerateAndroidRemapNativeCode.stamp"> - + <_GeneratePackageManagerJavaInputs Include="@(_GenerateJavaStubsInputs)" /> + <_GeneratePackageManagerJavaInputs Include="$(_XARemapMembersFilePath)" Condition=" '@(_AndroidRemapMembers->Count())' != '0' " />