diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 4be55630c91..2ce0fe4f1db 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -24,25 +24,21 @@ _PrepareNativeAssemblySources; $(_AfterPrepareAssemblies); _GetGenerateJavaStubsInputs; + _GetGenerateJavaCallableWrappersInputs; + _GetGenerateJavaStubsCoreInputs; + _GetGenerateTypeMappingsInputs; + _GetGenerateAndroidManifestInputs; + _GenerateJavaCallableWrappers; + _GenerateJavaStubsCore; + _GenerateTypeMappings; + _GenerateAndroidManifest; - - - - <_ManifestOutput Condition=" '$(AndroidManifestMerger)' == 'legacy' ">$(IntermediateOutputPath)android\AndroidManifest.xml - <_ManifestOutput Condition=" '$(AndroidManifestMerger)' != 'legacy' ">$(IntermediateOutputPath)AndroidManifest.xml - <_LinkingEnabled Condition=" '$(AndroidLinkMode)' != 'None'">True - <_LinkingEnabled Condition=" '$(AndroidLinkMode)' == 'None'">False - <_HaveMultipleRIDs Condition=" '$(RuntimeIdentifiers)' != '' ">True - <_HaveMultipleRIDs Condition=" '$(RuntimeIdentifiers)' == '' ">False - - - <_MergedManifestDocuments Condition=" '$(AndroidManifestMerger)' == 'legacy' " Include="@(ExtractedManifestDocuments)" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ManifestOutput Condition=" '$(AndroidManifestMerger)' == 'legacy' ">$(IntermediateOutputPath)android\AndroidManifest.xml + <_ManifestOutput Condition=" '$(AndroidManifestMerger)' != 'legacy' ">$(IntermediateOutputPath)AndroidManifest.xml + + + <_MergedManifestDocuments Condition=" '$(AndroidManifestMerger)' == 'legacy' " Include="@(ExtractedManifestDocuments)" /> + + - - - - + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets index 51cae6aab85..3b2162ce8d4 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets @@ -17,12 +17,42 @@ tasks needed by all typemap paths, but they currently depend on NativeCodeGenState from the Cecil-based GenerateJavaStubs task. Extracting them into a shared target requires decoupling from NativeCodeGenState first. See #10807. --> + + + + + + + + + + + + + + + + + + + + - - + DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateJavaStubsInputs;_GenerateJavaCallableWrappers;_GenerateJavaStubsCore;_GenerateTypeMappings;_GenerateAndroidManifest"> + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs index 49402865722..6bc20afbf9f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs @@ -22,6 +22,7 @@ sealed class Config public string? AssemblerPath; public string? AssemblerOptions; public string? InputSource; + public string? OutputFile; } [Required] @@ -43,6 +44,14 @@ public override System.Threading.Tasks.Task RunTaskAsync () void RunAssembler (Config config) { + if (config.OutputFile is not null && File.Exists (config.OutputFile)) { + string sourceFile = Path.Combine (WorkingDirectory, Path.GetFileName (config.InputSource)); + if (File.Exists (sourceFile) && File.GetLastWriteTimeUtc (config.OutputFile) >= File.GetLastWriteTimeUtc (sourceFile)) { + LogDebugMessage ($"[LLVM llc] Skipping '{Path.GetFileName (config.InputSource)}' because '{Path.GetFileName (config.OutputFile)}' is up to date"); + return; + } + } + var stdout_completed = new ManualResetEvent (false); var stderr_completed = new ManualResetEvent (false); var psi = new ProcessStartInfo () { @@ -118,10 +127,13 @@ IEnumerable GetAssemblerConfigs () string executableDir = Path.GetDirectoryName (llcPath); string executableName = MonoAndroidHelper.GetExecutablePath (executableDir, Path.GetFileName (llcPath)); + string outputFilePath = Path.Combine (WorkingDirectory, sourceFile.Replace (".ll", ".o")); + yield return new Config { InputSource = item.ItemSpec, AssemblerPath = Path.Combine (executableDir, executableName), AssemblerOptions = $"{assemblerOptions} -o={outputFile} {QuoteFileName (sourceFile)}", + OutputFile = outputFilePath, }; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs index a17945d8cee..c0249a1a4a1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs @@ -57,6 +57,7 @@ public class GenerateNativeApplicationConfigSources : AndroidTask public bool EnableMarshalMethods { get; set; } public bool EnableManagedMarshalMethodsLookup { get; set; } + public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } public string? RuntimeConfigBinFilePath { get; set; } public string ProjectRuntimeConfigFilePath { get; set; } = String.Empty; public string? BoundExceptionType { get; set; } @@ -251,7 +252,7 @@ public override bool RunTask () UsesAssemblyPreload = envBuilder.Parser.UsesAssemblyPreload, AndroidPackageName = AndroidPackageName, PackageNamingPolicy = pnp, - JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + JniAddNativeMethodRegistrationAttributePresent = JniAddNativeMethodRegistrationAttributePresent, NumberOfAssembliesInApk = assemblyCount, BundledAssemblyNameWidth = assemblyNameWidth, NativeLibraries = uniqueNativeLibraries, @@ -277,7 +278,7 @@ public override bool RunTask () BrokenExceptionTransitions = envBuilder.Parser.BrokenExceptionTransitions, PackageNamingPolicy = pnp, BoundExceptionType = boundExceptionType, - JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + JniAddNativeMethodRegistrationAttributePresent = JniAddNativeMethodRegistrationAttributePresent, HaveRuntimeConfigBlob = haveRuntimeConfigBlob, NumberOfAssembliesInApk = assemblyCount, BundledAssemblyNameWidth = assemblyNameWidth, diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs index 70a6a60f5a9..beacfd442a3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs @@ -31,6 +31,9 @@ public class GenerateTypeMappings : AndroidTask [Required] public string IntermediateOutputDirectory { get; set; } = ""; + [Output] + public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } + public bool SkipJniAddNativeMethodRegistrationAttributeScan { get; set; } [Required] @@ -102,6 +105,7 @@ void GenerateTypeMap (AndroidTargetArch arch, List assemblies) // Set for use by task later NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = state.JniAddNativeMethodRegistrationAttributePresent; + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent; AddOutputTypeMaps (tmg, state.TargetArch); } @@ -126,8 +130,10 @@ void GenerateAllTypeMappingsFromNativeState (bool useMarshalMethods) throw new InvalidOperationException ($"Internal error: no native code generator state defined"); // Set for use by task later - if (useMarshalMethods) + if (useMarshalMethods) { NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState.JniAddNativeMethodRegistrationAttributePresent; + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent; + } } void GenerateTypeMapFromNativeState (NativeCodeGenState state, bool useMarshalMethods) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index f04aabcb3dd..87d656b3a45 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -543,7 +543,7 @@ protected override void OnClick() Assert.IsFalse (StringAssertEx.ContainsText (b.LastBuildOutput, "AndroidResgen: Warning while updating Resource XML"), "Warning while processing resources should not have been raised."); Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true), "Build should have succeeded."); - Assert.IsTrue (b.Output.IsTargetSkipped ("_GenerateJavaStubs"), "Target _GenerateJavaStubs should have been skipped"); + Assert.IsTrue (b.Output.IsTargetSkipped ("_GenerateJavaStubsCore"), "Target _GenerateJavaStubsCore should have been skipped"); lib.Touch ("CustomTextView.cs"); 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 8e3600f20dd..1b4e3314598 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 @@ -746,7 +746,7 @@ public void ProduceReferenceAssembly ([Values] AndroidRuntime runtime) appBuilder.Output.AssertTargetIsSkipped ("CoreCompile"); appBuilder.Output.AssertTargetIsSkipped ("_BuildLibraryImportsCache"); appBuilder.Output.AssertTargetIsSkipped ("_ResolveLibraryProjectImports"); - appBuilder.Output.AssertTargetIsSkipped ("_GenerateJavaStubs"); + appBuilder.Output.AssertTargetIsSkipped ("_GenerateJavaStubsCore"); appBuilder.Output.AssertTargetIsPartiallyBuilt (KnownTargets.LinkAssembliesNoShrink); @@ -1237,7 +1237,10 @@ public void GenerateJavaStubsAndAssembly ([Values] bool isRelease, [Values] Andr } var targets = new [] { - "_GenerateJavaStubs", + "_GenerateJavaCallableWrappers", + "_GenerateJavaStubsCore", + "_GenerateTypeMappings", + "_GenerateAndroidManifest", "_GeneratePackageManagerJava", }; var proj = new XamarinAndroidApplicationProject { @@ -1289,6 +1292,34 @@ public void GenerateJavaStubsAndAssembly ([Values] bool isRelease, [Values] Andr } } + [Test] + public void GenerateJavaStubsSubTargetIncrementality ([Values (false, true)] bool isRelease) + { + // Test that all sub-targets correctly skip on no-change rebuilds. + var targets = new [] { + "_GenerateJavaCallableWrappers", + "_GenerateJavaStubsCore", + "_GenerateTypeMappings", + "_GenerateAndroidManifest", + }; + var proj = new XamarinAndroidApplicationProject { + IsRelease = isRelease, + }; + + using (var b = CreateApkBuilder ()) { + Assert.IsTrue (b.Build (proj), "first build should have succeeded."); + foreach (var target in targets) { + Assert.IsFalse (b.Output.IsTargetSkipped (target), $"first build: `{target}` should *not* be skipped!"); + } + + // No-change rebuild: all sub-targets should skip + Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "no-change rebuild should have succeeded."); + foreach (var target in targets) { + Assert.IsTrue (b.Output.IsTargetSkipped (target), $"no-change: `{target}` should be skipped!"); + } + } + } + readonly string [] ExpectedAssemblyFiles = new [] { Path.Combine ("android", "environment.@ABI@.o"), Path.Combine ("android", "environment.@ABI@.ll"), @@ -1683,7 +1714,7 @@ public void AndroidResourceChange ([Values] AndroidRuntime runtime) // TODO: NativeAOT doesn't skip this target if (runtime != AndroidRuntime.NativeAOT) { - builder.Output.AssertTargetIsSkipped ("_GenerateJavaStubs"); + builder.Output.AssertTargetIsSkipped ("_GenerateJavaStubsCore"); } builder.Output.AssertTargetIsSkipped ("_CompileJava"); builder.Output.AssertTargetIsSkipped ("_CompileToDalvik"); diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index e2cd6eeca42..2c244a226f0 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1493,6 +1493,48 @@ because xbuild doesn't support framework reference assemblies. + + + <_GenerateJavaCallableWrappersInputs Include="@(_AndroidMSBuildAllProjects)" /> + <_GenerateJavaCallableWrappersInputs Include="$(_AndroidBuildPropertiesCache)" /> + <_GenerateJavaCallableWrappersInputs Include="@(_ResolvedAssemblies->'$([System.IO.Path]::ChangeExtension("%(Identity)", ".jlo.xml"))')" /> + + + + + + <_GenerateJavaStubsCoreInputs Include="@(_AndroidMSBuildAllProjects)" /> + <_GenerateJavaStubsCoreInputs Include="$(_ResolvedUserAssembliesHashFile)" /> + <_GenerateJavaStubsCoreInputs Include="@(_ResolvedUserMonoAndroidAssemblies)" /> + <_GenerateJavaStubsCoreInputs Include="$(_AndroidBuildPropertiesCache)" /> + <_GenerateJavaStubsCoreInputs Include="$(_AndroidManifestAbs)" /> + <_GenerateJavaStubsCoreInputs Include="@(AndroidEnvironment);@(LibraryEnvironments)" Condition=" '$(_AndroidFastDeployEnvironmentFiles)' != 'true' " /> + + + + + + <_GenerateTypeMappingsInputs Include="@(_AndroidMSBuildAllProjects)" /> + <_GenerateTypeMappingsInputs Include="$(_AndroidBuildPropertiesCache)" /> + <_GenerateTypeMappingsInputs Include="@(_ResolvedAssemblies->'$([System.IO.Path]::ChangeExtension("%(Identity)", ".typemap.xml"))')" /> + <_GenerateTypeMappingsInputs + Condition=" '$(_AndroidUseMarshalMethods)' == 'true' Or '$(_AndroidJLOCheckedBuild)' == 'true' " + Include="$(_AndroidStampDirectory)_GenerateJavaStubsCore.stamp" /> + + + + + + <_GenerateAndroidManifestInputs Include="@(_AndroidMSBuildAllProjects)" /> + <_GenerateAndroidManifestInputs Include="$(_AndroidManifestAbs)" /> + <_GenerateAndroidManifestInputs Include="$(_AndroidBuildPropertiesCache)" /> + <_GenerateAndroidManifestInputs Include="@(_ResolvedUserMonoAndroidAssemblies)" /> + <_GenerateAndroidManifestInputs Include="@(AndroidEnvironment);@(LibraryEnvironments)" Condition=" '$(_AndroidFastDeployEnvironmentFiles)' != 'true' " /> + + <_GenerateAndroidManifestInputs Include="$(_AndroidStampDirectory)_GenerateJavaStubsCore.stamp" /> + + + + + + + +