22using System ;
33using System . Collections . Concurrent ;
44using System . Collections . Generic ;
5+ using System . Diagnostics ;
56using System . IO ;
7+ using System . Linq ;
68using Java . Interop . Tools . Cecil ;
79using Microsoft . Android . Build . Tasks ;
810using Microsoft . Build . Framework ;
@@ -20,48 +22,99 @@ public class GenerateTypeMappings : AndroidTask
2022
2123 public bool Debug { get ; set ; }
2224
25+ [ Output ]
26+ public ITaskItem [ ] GeneratedBinaryTypeMaps { get ; set ; } = [ ] ;
27+
2328 [ Required ]
2429 public string IntermediateOutputDirectory { get ; set ; } = "" ;
2530
2631 public bool SkipJniAddNativeMethodRegistrationAttributeScan { get ; set ; }
2732
2833 [ Required ]
29- public string TypemapOutputDirectory { get ; set ; } = "" ;
34+ public ITaskItem [ ] ResolvedAssemblies { get ; set ; } = [ ] ;
3035
31- [ Output ]
32- public ITaskItem [ ] GeneratedBinaryTypeMaps { get ; set ; } = [ ] ;
36+ // This property is temporary and is used to ensure that the new "linker step"
37+ // JLO scanning produces the same results as the old process. It will be removed
38+ // once the process is complete.
39+ public bool RunCheckedBuild { get ; set ; }
40+
41+ [ Required ]
42+ public string [ ] SupportedAbis { get ; set ; } = [ ] ;
3343
3444 public string TypemapImplementation { get ; set ; } = "llvm-ir" ;
3545
46+ [ Required ]
47+ public string TypemapOutputDirectory { get ; set ; } = "" ;
48+
3649 AndroidRuntime androidRuntime ;
3750
3851 public override bool RunTask ( )
3952 {
40- androidRuntime = MonoAndroidHelper . ParseAndroidRuntime ( AndroidRuntime ) ;
53+ // Temporarily used to ensure we still generate the same as the old code
54+ if ( RunCheckedBuild ) {
55+ androidRuntime = MonoAndroidHelper . ParseAndroidRuntime ( AndroidRuntime ) ;
56+
57+ // Retrieve the stored NativeCodeGenState
58+ var nativeCodeGenStates = BuildEngine4 . GetRegisteredTaskObjectAssemblyLocal < ConcurrentDictionary < AndroidTargetArch , NativeCodeGenState > > (
59+ MonoAndroidHelper . GetProjectBuildSpecificTaskObjectKey ( GenerateJavaStubs . NativeCodeGenStateRegisterTaskKey , WorkingDirectory , IntermediateOutputDirectory ) ,
60+ RegisteredTaskObjectLifetime . Build
61+ ) ;
62+
63+ NativeCodeGenState ? templateCodeGenState = null ;
64+
65+ foreach ( var kvp in nativeCodeGenStates ) {
66+ NativeCodeGenState state = kvp . Value ;
67+ templateCodeGenState = state ;
68+ WriteTypeMappings ( state ) ;
69+ }
4170
42- // Retrieve the stored NativeCodeGenState
43- var nativeCodeGenStates = BuildEngine4 . GetRegisteredTaskObjectAssemblyLocal < ConcurrentDictionary < AndroidTargetArch , NativeCodeGenState > > (
44- MonoAndroidHelper . GetProjectBuildSpecificTaskObjectKey ( GenerateJavaStubs . NativeCodeGenStateRegisterTaskKey , WorkingDirectory , IntermediateOutputDirectory ) ,
45- RegisteredTaskObjectLifetime . Build
46- ) ;
71+ if ( templateCodeGenState is null )
72+ throw new InvalidOperationException ( $ "Internal error: no native code generator state defined") ;
4773
48- NativeCodeGenState ? templateCodeGenState = null ;
74+ // Set for use by <GeneratePackageManagerJava/> task later
75+ NativeCodeGenState . TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState . JniAddNativeMethodRegistrationAttributePresent ;
4976
50- foreach ( var kvp in nativeCodeGenStates ) {
51- NativeCodeGenState state = kvp . Value ;
52- templateCodeGenState = state ;
53- WriteTypeMappings ( state ) ;
77+ return ! Log . HasLoggedErrors ;
5478 }
5579
56- if ( templateCodeGenState is null )
57- throw new InvalidOperationException ( $ "Internal error: no native code generator state defined") ;
80+ if ( androidRuntime == Xamarin . Android . Tasks . AndroidRuntime . NativeAOT ) {
81+ // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep`
82+ Log . LogDebugMessage ( "Skipping type maps for NativeAOT." ) ;
83+ return ! Log . HasLoggedErrors ;
84+ }
5885
59- // Set for use by <GeneratePackageManagerJava/> task later
60- NativeCodeGenState . TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState . JniAddNativeMethodRegistrationAttributePresent ;
86+ GenerateAllTypeMappings ( ) ;
6187
6288 return ! Log . HasLoggedErrors ;
6389 }
6490
91+ void GenerateAllTypeMappings ( )
92+ {
93+ var allAssembliesPerArch = MonoAndroidHelper . GetPerArchAssemblies ( ResolvedAssemblies , SupportedAbis , validate : true ) ;
94+
95+ foreach ( var set in allAssembliesPerArch )
96+ GenerateTypeMap ( set . Key , set . Value . Values . ToList ( ) ) ;
97+ }
98+
99+ void GenerateTypeMap ( AndroidTargetArch arch , List < ITaskItem > assemblies )
100+ {
101+ Log . LogDebugMessage ( $ "Generating type maps for architecture '{ arch } '") ;
102+
103+ var sw = Stopwatch . StartNew ( ) ;
104+ var state = TypeMapObjectsFileAdapter . Create ( arch , assemblies , Log ) ;
105+ Log . LogDebugMessage ( $ "Type map deserialization took { sw . ElapsedMilliseconds } ms") ;
106+ sw . Restart ( ) ;
107+ // An error was already logged to Log.LogError
108+ if ( state is null )
109+ return ;
110+
111+ var tmg = new TypeMapGenerator ( Log , state , androidRuntime ) ;
112+ tmg . Generate ( Debug , SkipJniAddNativeMethodRegistrationAttributeScan , TypemapOutputDirectory ) ;
113+
114+ Log . Equals ( $ "Type map generation took { sw . ElapsedMilliseconds } ms") ;
115+ AddOutputTypeMaps ( tmg , state . TargetArch ) ;
116+ }
117+
65118 void WriteTypeMappings ( NativeCodeGenState state )
66119 {
67120 if ( androidRuntime == Xamarin . Android . Tasks . AndroidRuntime . NativeAOT ) {
@@ -76,11 +129,17 @@ void WriteTypeMappings (NativeCodeGenState state)
76129 state = new NativeCodeGenState ( state . TargetArch , new TypeDefinitionCache ( ) , state . Resolver , [ ] , [ ] , state . Classifier ) ;
77130 }
78131
79- var tmg = new TypeMapGenerator ( Log , state , androidRuntime ) ;
132+ var tmg = new TypeMapGenerator ( Log , new NativeCodeGenStateAdapter ( state ) , androidRuntime ) ;
80133 tmg . Generate ( Debug , SkipJniAddNativeMethodRegistrationAttributeScan , TypemapOutputDirectory ) ;
81134
82- string abi = MonoAndroidHelper . ArchToAbi ( state . TargetArch ) ;
135+ AddOutputTypeMaps ( tmg , state . TargetArch ) ;
136+ }
137+
138+ void AddOutputTypeMaps ( TypeMapGenerator tmg , AndroidTargetArch arch )
139+ {
140+ string abi = MonoAndroidHelper . ArchToAbi ( arch ) ;
83141 var items = new List < ITaskItem > ( ) ;
142+
84143 foreach ( string file in tmg . GeneratedBinaryTypeMaps ) {
85144 var item = new TaskItem ( file ) ;
86145 string fileName = Path . GetFileName ( file ) ;
0 commit comments