Skip to content

Commit b63c601

Browse files
[xabt] Move StripEmbeddedLibraries trimmer step to MSBuild task (#10894)
Move embedded resource stripping out of the ILLink custom step so it runs after ILLink but before ReadyToRun/crossgen2 in the inner build, ensuring R2R images are generated from already-stripped assemblies. - Trimmed builds: new StripEmbeddedLibraries MSBuild task runs via _StripEmbeddedLibraries target (AfterTargets="ILLink") in the inner build, processing assemblies in-place with temp-write-copy-back. - Non-trimmed builds: new StripEmbeddedLibrariesStep added to LinkAssembliesNoShrink pipeline. - Shared ShouldStripResource() logic between both paths. - Removed old _TrimmerCustomSteps registration and deleted the ILLink StripEmbeddedLibraries.cs (now dead code). Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
1 parent d8d514e commit b63c601

File tree

3 files changed

+133
-57
lines changed

3 files changed

+133
-57
lines changed

src/Microsoft.Android.Sdk.ILLink/StripEmbeddedLibraries.cs

Lines changed: 0 additions & 56 deletions
This file was deleted.

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<UsingTask TaskName="Xamarin.Android.Tasks.GetMonoPlatformJar" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
88
<UsingTask TaskName="Xamarin.Android.Tasks.RemoveRegisterAttribute" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
99
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateProguardConfiguration" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
10+
<UsingTask TaskName="Xamarin.Android.Tasks.StripEmbeddedLibraries" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
1011

1112
<PropertyGroup>
1213
<_RemoveRegisterFlag>$(MonoAndroidIntermediateAssemblyDir)shrunk\shrunk.flag</_RemoveRegisterFlag>
@@ -203,7 +204,6 @@
203204
Type="MonoDroid.Tuner.AddKeepAlivesStep"
204205
/>
205206
<!-- Custom steps that run after CleanStep -->
206-
<_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" AfterStep="CleanStep" Type="MonoDroid.Tuner.StripEmbeddedLibraries" />
207207
<_TrimmerCustomSteps
208208
Condition=" '$(AndroidLinkResources)' == 'true' "
209209
Include="$(_AndroidLinkerCustomStepAssembly)"
@@ -250,6 +250,22 @@
250250
<Touch Files="$(_AndroidLinkFlag)" AlwaysCreate="true" />
251251
</Target>
252252

253+
<!--
254+
Strip embedded Android resources (.jar, native libs, etc.) from trimmed assemblies.
255+
Runs in the inner build after ILLink but before ReadyToRun/crossgen2 compilation,
256+
so R2R images are generated from already-stripped assemblies.
257+
-->
258+
<Target Name="_StripEmbeddedLibraries"
259+
AfterTargets="ILLink"
260+
Condition=" '$(PublishTrimmed)' == 'true' ">
261+
<ItemGroup>
262+
<_StripEmbeddedLibrariesAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " />
263+
</ItemGroup>
264+
<StripEmbeddedLibraries
265+
Assemblies="@(_StripEmbeddedLibrariesAssembly)"
266+
Deterministic="$(Deterministic)" />
267+
</Target>
268+
253269
<!-- Inject _TypeMapKind into the property cache -->
254270
<Target Name="_SetTypemapProperties"
255271
BeforeTargets="_CreatePropertiesCache">
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#nullable enable
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using Microsoft.Android.Build.Tasks;
8+
using Microsoft.Build.Framework;
9+
using Microsoft.Build.Utilities;
10+
using Mono.Cecil;
11+
12+
namespace Xamarin.Android.Tasks;
13+
14+
/// <summary>
15+
/// An MSBuild task that strips embedded Android resources (.jar, __AndroidNativeLibraries__.zip,
16+
/// __AndroidLibraryProjects__.zip, __AndroidEnvironment__) from trimmed assemblies.
17+
///
18+
/// This runs in the inner build after ILLink but before ReadyToRun/crossgen2 compilation,
19+
/// so that R2R images are generated from the already-stripped assemblies.
20+
/// </summary>
21+
public class StripEmbeddedLibraries : AndroidTask
22+
{
23+
public override string TaskPrefix => "SEL";
24+
25+
[Required]
26+
public ITaskItem [] Assemblies { get; set; } = [];
27+
28+
public bool Deterministic { get; set; }
29+
30+
public override bool RunTask ()
31+
{
32+
var resolver = new DefaultAssemblyResolver ();
33+
var searchDirectories = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
34+
35+
foreach (var assembly in Assemblies) {
36+
var dir = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec) ?? "");
37+
if (searchDirectories.Add (dir)) {
38+
resolver.AddSearchDirectory (dir);
39+
}
40+
}
41+
42+
try {
43+
foreach (var assembly in Assemblies) {
44+
if (MonoAndroidHelper.IsFrameworkAssembly (assembly)) {
45+
continue;
46+
}
47+
48+
StripAssembly (assembly.ItemSpec, resolver);
49+
}
50+
} finally {
51+
resolver.Dispose ();
52+
}
53+
54+
return !Log.HasLoggedErrors;
55+
}
56+
57+
void StripAssembly (string assemblyPath, IAssemblyResolver resolver)
58+
{
59+
string pdbPath = Path.ChangeExtension (assemblyPath, ".pdb");
60+
bool havePdb = File.Exists (pdbPath);
61+
62+
var readerParams = new ReaderParameters {
63+
ReadSymbols = havePdb,
64+
ReadWrite = true,
65+
AssemblyResolver = resolver,
66+
};
67+
68+
bool assembly_modified = false;
69+
70+
using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath, readerParams)) {
71+
foreach (var module in assembly.Modules) {
72+
foreach (var resource in module.Resources.ToArray ()) {
73+
if (ShouldStripResource (resource)) {
74+
Log.LogDebugMessage ($" Stripped {resource.Name} from {assembly.Name.Name}.dll");
75+
module.Resources.Remove (resource);
76+
assembly_modified = true;
77+
}
78+
}
79+
}
80+
81+
if (!assembly_modified) {
82+
return;
83+
}
84+
85+
Log.LogDebugMessage ($" Writing stripped assembly: {assemblyPath}");
86+
assembly.Write (new WriterParameters {
87+
WriteSymbols = havePdb,
88+
DeterministicMvid = Deterministic,
89+
});
90+
}
91+
}
92+
93+
/// <summary>
94+
/// Determines whether a resource should be stripped from the assembly.
95+
/// Matches the same criteria as the old ILLink StripEmbeddedLibraries step.
96+
/// </summary>
97+
internal static bool ShouldStripResource (Resource resource)
98+
{
99+
if (!(resource is EmbeddedResource))
100+
return false;
101+
// Embedded jars
102+
if (resource.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase))
103+
return true;
104+
// Embedded AndroidNativeLibrary archive
105+
if (resource.Name == "__AndroidNativeLibraries__.zip")
106+
return true;
107+
// Embedded AndroidResourceLibrary archive
108+
if (resource.Name == "__AndroidLibraryProjects__.zip")
109+
return true;
110+
// Embedded AndroidEnvironment items
111+
if (resource.Name.StartsWith ("__AndroidEnvironment__", StringComparison.Ordinal))
112+
return true;
113+
return false;
114+
}
115+
116+
}

0 commit comments

Comments
 (0)