Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,21 @@
_PrepareNativeAssemblySources;
$(_AfterPrepareAssemblies);
_GetGenerateJavaStubsInputs;
_GetGenerateJavaCallableWrappersInputs;
_GetGenerateJavaStubsCoreInputs;
_GetGenerateTypeMappingsInputs;
_GetGenerateAndroidManifestInputs;
_GenerateJavaCallableWrappers;
_GenerateJavaStubsCore;
_GenerateTypeMappings;
_GenerateAndroidManifest;
</_GenerateJavaStubsDependsOnTargets>
</PropertyGroup>

<Target Name="_GenerateJavaStubs"
DependsOnTargets="$(_GenerateJavaStubsDependsOnTargets);$(BeforeGenerateAndroidManifest)"
Inputs="@(_GenerateJavaStubsInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp">

<PropertyGroup>
<_ManifestOutput Condition=" '$(AndroidManifestMerger)' == 'legacy' ">$(IntermediateOutputPath)android\AndroidManifest.xml</_ManifestOutput>
<_ManifestOutput Condition=" '$(AndroidManifestMerger)' != 'legacy' ">$(IntermediateOutputPath)AndroidManifest.xml</_ManifestOutput>
<_LinkingEnabled Condition=" '$(AndroidLinkMode)' != 'None'">True</_LinkingEnabled>
<_LinkingEnabled Condition=" '$(AndroidLinkMode)' == 'None'">False</_LinkingEnabled>
<_HaveMultipleRIDs Condition=" '$(RuntimeIdentifiers)' != '' ">True</_HaveMultipleRIDs>
<_HaveMultipleRIDs Condition=" '$(RuntimeIdentifiers)' == '' ">False</_HaveMultipleRIDs>
</PropertyGroup>
<ItemGroup>
<_MergedManifestDocuments Condition=" '$(AndroidManifestMerger)' == 'legacy' " Include="@(ExtractedManifestDocuments)" />
</ItemGroup>
<Target Name="_GenerateJavaCallableWrappers"
DependsOnTargets="_PrepareAssemblies;_GetGenerateJavaCallableWrappersInputs"
Inputs="@(_GenerateJavaCallableWrappersInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaCallableWrappers.stamp">

<GenerateJavaCallableWrappers
CodeGenerationTarget="$(_AndroidJcwCodegenTarget)"
Expand All @@ -60,6 +56,16 @@
SupportedAbis="@(_BuildTargetAbis)">
</GenerateACWMap>

<Touch Files="$(_AndroidStampDirectory)_GenerateJavaCallableWrappers.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateJavaStubsCore"
DependsOnTargets="_PrepareAssemblies;_GetGenerateJavaStubsInputs;_GetGenerateJavaStubsCoreInputs"
Inputs="@(_GenerateJavaStubsCoreInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubsCore.stamp">

<!-- GeneratedJavaFiles may be empty when _GenerateJavaCallableWrappers is skipped;
safe because it's only used in RunCheckedBuild validation -->
<GenerateJavaStubs
CodeGenerationTarget="$(_AndroidJcwCodegenTarget)"
ResolvedAssemblies="@(_ResolvedAssemblies)"
Expand All @@ -85,6 +91,14 @@
IntermediateOutputDirectory="$(IntermediateOutputPath)">
</RewriteMarshalMethods>

<Touch Files="$(_AndroidStampDirectory)_GenerateJavaStubsCore.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateTypeMappings"
DependsOnTargets="_GenerateJavaStubsCore;_PrepareNativeAssemblySources;_GetGenerateTypeMappingsInputs"
Inputs="@(_GenerateTypeMappingsInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateTypeMappings.stamp">

<GenerateTypeMappings
AndroidRuntime="$(_AndroidRuntime)"
Debug="$(AndroidIncludeDebugSymbols)"
Expand All @@ -96,8 +110,40 @@
SupportedAbis="@(_BuildTargetAbis)"
TypemapImplementation="$(_AndroidTypeMapImplementation)"
TypemapOutputDirectory="$(_NativeAssemblySourceDir)">
<Output TaskParameter="JniAddNativeMethodRegistrationAttributePresent" PropertyName="_JniAddNativeMethodRegistrationAttributePresent" />
</GenerateTypeMappings>

<!-- Persist the JNI registration flag for downstream targets that may run
even when this target is skipped on subsequent incremental builds -->
<WriteLinesToFile
File="$(IntermediateOutputPath)jni-registration-attribute.cache"
Lines="$(_JniAddNativeMethodRegistrationAttributePresent)"
Overwrite="true"
WriteOnlyWhenDifferent="true" />

<ItemGroup>
<FileWrites Include="@(_TypeMapAssemblySource)" />
<FileWrites Include="@(_TypeMapAssemblyInclude)" />
<FileWrites Include="@(_AndroidTypeMapping)" Condition=" '@(_AndroidTypeMapping->Count())' == '0' " />
<FileWrites Include="$(IntermediateOutputPath)jni-registration-attribute.cache" />
</ItemGroup>

<Touch Files="$(_AndroidStampDirectory)_GenerateTypeMappings.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateAndroidManifest"
DependsOnTargets="_GenerateJavaStubsCore;_GetGenerateJavaStubsInputs;$(BeforeGenerateAndroidManifest);_GetGenerateAndroidManifestInputs"
Inputs="@(_GenerateAndroidManifestInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateAndroidManifest.stamp">

<PropertyGroup>
<_ManifestOutput Condition=" '$(AndroidManifestMerger)' == 'legacy' ">$(IntermediateOutputPath)android\AndroidManifest.xml</_ManifestOutput>
<_ManifestOutput Condition=" '$(AndroidManifestMerger)' != 'legacy' ">$(IntermediateOutputPath)AndroidManifest.xml</_ManifestOutput>
</PropertyGroup>
<ItemGroup>
<_MergedManifestDocuments Condition=" '$(AndroidManifestMerger)' == 'legacy' " Include="@(ExtractedManifestDocuments)" />
</ItemGroup>

<GenerateACWMap
Condition=" '$(_AndroidJLOCheckedBuild)' == 'true' "
AcwMapFile="$(_AcwMapFile)"
Expand Down Expand Up @@ -147,13 +193,16 @@
</GenerateAdditionalProviderSources>

<ItemGroup>
<FileWrites Include="@(_TypeMapAssemblySource)" />
<FileWrites Include="@(_TypeMapAssemblyInclude)" />
<FileWrites Include="@(_AndroidTypeMapping)" Condition=" '@(_AndroidTypeMapping->Count())' == '0' " />
<FileWrites Include="$(_ManifestOutput)" />
</ItemGroup>

<Touch Files="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp" AlwaysCreate="True" />
<Touch Files="$(_AndroidStampDirectory)_GenerateAndroidManifest.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateJavaStubs"
DependsOnTargets="$(_GenerateJavaStubsDependsOnTargets)">
<!-- This target is preserved for backward compatibility.
All work is done by the sub-targets listed in _GenerateJavaStubsDependsOnTargets. -->
</Target>

<!-- ILLink customization: custom trimmer steps, root descriptors, etc. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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. -->
<Target Name="_GenerateJavaCallableWrappers"
DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateJavaCallableWrappersInputs"
Inputs="@(_GenerateJavaCallableWrappersInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaCallableWrappers.stamp">
<Message Text="Trimmable typemap: skipping _GenerateJavaCallableWrappers" Importance="High" />
<Touch Files="$(_AndroidStampDirectory)_GenerateJavaCallableWrappers.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateJavaStubsCore"
DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateJavaStubsCoreInputs"
Inputs="@(_GenerateJavaStubsCoreInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubsCore.stamp">
<Message Text="Trimmable typemap: skipping _GenerateJavaStubsCore" Importance="High" />
<Touch Files="$(_AndroidStampDirectory)_GenerateJavaStubsCore.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateTypeMappings"
DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateTypeMappingsInputs"
Inputs="@(_GenerateTypeMappingsInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateTypeMappings.stamp">
<Message Text="Trimmable typemap: skipping _GenerateTypeMappings" Importance="High" />
<Touch Files="$(_AndroidStampDirectory)_GenerateTypeMappings.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateAndroidManifest"
DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateAndroidManifestInputs"
Inputs="@(_GenerateAndroidManifestInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateAndroidManifest.stamp">
<Message Text="Trimmable typemap: skipping _GenerateAndroidManifest" Importance="High" />
<Touch Files="$(_AndroidStampDirectory)_GenerateAndroidManifest.stamp" AlwaysCreate="True" />
</Target>

<Target Name="_GenerateJavaStubs"
DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateJavaStubsInputs"
Inputs="@(_GenerateJavaStubsInputs)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp">
<Message Text="Trimmable typemap: skipping legacy _GenerateJavaStubs" Importance="High" />
<Touch Files="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp" AlwaysCreate="True" />
DependsOnTargets="_SetLatestTargetFrameworkVersion;_PrepareAssemblies;_GetGenerateJavaStubsInputs;_GenerateJavaCallableWrappers;_GenerateJavaStubsCore;_GenerateTypeMappings;_GenerateAndroidManifest">
<!-- This target is preserved for backward compatibility.
In the trimmable typemap path, all sub-targets are stubs. -->
</Target>

</Project>
12 changes: 12 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ sealed class Config
public string? AssemblerPath;
public string? AssemblerOptions;
public string? InputSource;
public string? OutputFile;
}

[Required]
Expand All @@ -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 () {
Expand Down Expand Up @@ -118,10 +127,13 @@ IEnumerable<Config> 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,
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -102,6 +105,7 @@ void GenerateTypeMap (AndroidTargetArch arch, List<ITaskItem> assemblies)

// Set for use by <GeneratePackageManagerJava/> task later
NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = state.JniAddNativeMethodRegistrationAttributePresent;
JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent;

AddOutputTypeMaps (tmg, state.TargetArch);
}
Expand All @@ -126,8 +130,10 @@ void GenerateAllTypeMappingsFromNativeState (bool useMarshalMethods)
throw new InvalidOperationException ($"Internal error: no native code generator state defined");

// Set for use by <GenerateNativeApplicationConfigSources/> task later
if (useMarshalMethods)
if (useMarshalMethods) {
NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState.JniAddNativeMethodRegistrationAttributePresent;
JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent;
}
}

void GenerateTypeMapFromNativeState (NativeCodeGenState state, bool useMarshalMethods)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -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");
Expand Down
Loading