3
3
using System . Collections . Concurrent ;
4
4
using System . Collections . Generic ;
5
5
using System . IO ;
6
+ using System . Linq ;
6
7
using Java . Interop . Tools . Cecil ;
7
8
using Microsoft . Android . Build . Tasks ;
8
9
using Microsoft . Build . Framework ;
11
12
12
13
namespace Xamarin . Android . Tasks ;
13
14
15
+ // Note: If/When this is converted to an incremental task, every build still needs to set:
16
+ // NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent
14
17
public class GenerateTypeMappings : AndroidTask
15
18
{
16
19
public override string TaskPrefix => "GTM" ;
@@ -20,25 +23,86 @@ public class GenerateTypeMappings : AndroidTask
20
23
21
24
public bool Debug { get ; set ; }
22
25
26
+ public bool EnableMarshalMethods { get ; set ; }
27
+
28
+ [ Output ]
29
+ public ITaskItem [ ] GeneratedBinaryTypeMaps { get ; set ; } = [ ] ;
30
+
23
31
[ Required ]
24
32
public string IntermediateOutputDirectory { get ; set ; } = "" ;
25
33
26
34
public bool SkipJniAddNativeMethodRegistrationAttributeScan { get ; set ; }
27
35
28
36
[ Required ]
29
- public string TypemapOutputDirectory { get ; set ; } = "" ;
37
+ public ITaskItem [ ] ResolvedAssemblies { get ; set ; } = [ ] ;
30
38
31
- [ Output ]
32
- public ITaskItem [ ] GeneratedBinaryTypeMaps { get ; set ; } = [ ] ;
39
+ // This property is temporary and is used to ensure that the new "linker step"
40
+ // JLO scanning produces the same results as the old process. It will be removed
41
+ // once the process is complete.
42
+ public bool RunCheckedBuild { get ; set ; }
43
+
44
+ [ Required ]
45
+ public string [ ] SupportedAbis { get ; set ; } = [ ] ;
33
46
34
47
public string TypemapImplementation { get ; set ; } = "llvm-ir" ;
35
48
49
+ [ Required ]
50
+ public string TypemapOutputDirectory { get ; set ; } = "" ;
51
+
36
52
AndroidRuntime androidRuntime ;
37
53
38
54
public override bool RunTask ( )
39
55
{
56
+ var useMarshalMethods = ! Debug && EnableMarshalMethods ;
57
+
40
58
androidRuntime = MonoAndroidHelper . ParseAndroidRuntime ( AndroidRuntime ) ;
59
+ if ( androidRuntime == Xamarin . Android . Tasks . AndroidRuntime . NativeAOT ) {
60
+ // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep`
61
+ Log . LogDebugMessage ( "Skipping type maps for NativeAOT." ) ;
62
+ return ! Log . HasLoggedErrors ;
63
+ }
64
+
65
+ // If using marshal methods, we cannot use the .typemap.xml files currently because
66
+ // the type token ids were changed by the marshal method rewriter after we wrote the .xml files.
67
+ if ( ! useMarshalMethods )
68
+ GenerateAllTypeMappings ( ) ;
69
+
70
+ // Generate typemaps from the native code generator state (produced by the marshal method rewriter)
71
+ if ( RunCheckedBuild || useMarshalMethods )
72
+ GenerateAllTypeMappingsFromNativeState ( useMarshalMethods ) ;
73
+
74
+ return ! Log . HasLoggedErrors ;
75
+ }
76
+
77
+ void GenerateAllTypeMappings ( )
78
+ {
79
+ var allAssembliesPerArch = MonoAndroidHelper . GetPerArchAssemblies ( ResolvedAssemblies , SupportedAbis , validate : true ) ;
80
+
81
+ foreach ( var set in allAssembliesPerArch )
82
+ GenerateTypeMap ( set . Key , set . Value . Values . ToList ( ) ) ;
83
+ }
84
+
85
+ void GenerateTypeMap ( AndroidTargetArch arch , List < ITaskItem > assemblies )
86
+ {
87
+ Log . LogDebugMessage ( $ "Generating type maps for architecture '{ arch } '") ;
88
+
89
+ var state = TypeMapObjectsFileAdapter . Create ( arch , assemblies , Log ) ;
41
90
91
+ // An error was already logged to Log.LogError
92
+ if ( state is null )
93
+ return ;
94
+
95
+ var tmg = new TypeMapGenerator ( Log , state , androidRuntime ) ;
96
+ tmg . Generate ( Debug , SkipJniAddNativeMethodRegistrationAttributeScan , TypemapOutputDirectory ) ;
97
+
98
+ // Set for use by <GeneratePackageManagerJava/> task later
99
+ NativeCodeGenState . TemplateJniAddNativeMethodRegistrationAttributePresent = state . JniAddNativeMethodRegistrationAttributePresent ;
100
+
101
+ AddOutputTypeMaps ( tmg , state . TargetArch ) ;
102
+ }
103
+
104
+ void GenerateAllTypeMappingsFromNativeState ( bool useMarshalMethods )
105
+ {
42
106
// Retrieve the stored NativeCodeGenState
43
107
var nativeCodeGenStates = BuildEngine4 . GetRegisteredTaskObjectAssemblyLocal < ConcurrentDictionary < AndroidTargetArch , NativeCodeGenState > > (
44
108
MonoAndroidHelper . GetProjectBuildSpecificTaskObjectKey ( GenerateJavaStubs . NativeCodeGenStateRegisterTaskKey , WorkingDirectory , IntermediateOutputDirectory ) ,
@@ -50,37 +114,41 @@ public override bool RunTask ()
50
114
foreach ( var kvp in nativeCodeGenStates ) {
51
115
NativeCodeGenState state = kvp . Value ;
52
116
templateCodeGenState = state ;
53
- WriteTypeMappings ( state ) ;
117
+ GenerateTypeMapFromNativeState ( state , useMarshalMethods ) ;
54
118
}
55
119
56
120
if ( templateCodeGenState is null )
57
121
throw new InvalidOperationException ( $ "Internal error: no native code generator state defined") ;
58
122
59
123
// Set for use by <GeneratePackageManagerJava/> task later
60
124
NativeCodeGenState . TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState . JniAddNativeMethodRegistrationAttributePresent ;
61
-
62
- return ! Log . HasLoggedErrors ;
63
125
}
64
126
65
- void WriteTypeMappings ( NativeCodeGenState state )
127
+ void GenerateTypeMapFromNativeState ( NativeCodeGenState state , bool useMarshalMethods )
66
128
{
67
129
if ( androidRuntime == Xamarin . Android . Tasks . AndroidRuntime . NativeAOT ) {
68
130
// NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep`
69
131
Log . LogDebugMessage ( "Skipping type maps for NativeAOT." ) ;
70
132
return ;
71
133
}
72
- Log . LogDebugMessage ( $ "Generating type maps for architecture '{ state . TargetArch } '") ;
134
+ Log . LogDebugMessage ( $ "Generating type maps from native state for architecture '{ state . TargetArch } ' (RunCheckedBuild = { RunCheckedBuild } ) ") ;
73
135
74
136
if ( TypemapImplementation != "llvm-ir" ) {
75
137
Log . LogDebugMessage ( $ "TypemapImplementation='{ TypemapImplementation } ' will write an empty native typemap.") ;
76
138
state = new NativeCodeGenState ( state . TargetArch , new TypeDefinitionCache ( ) , state . Resolver , [ ] , [ ] , state . Classifier ) ;
77
139
}
78
140
79
- var tmg = new TypeMapGenerator ( Log , state , androidRuntime ) ;
141
+ var tmg = new TypeMapGenerator ( Log , new NativeCodeGenStateAdapter ( state ) , androidRuntime ) { RunCheckedBuild = RunCheckedBuild && ! useMarshalMethods } ;
80
142
tmg . Generate ( Debug , SkipJniAddNativeMethodRegistrationAttributeScan , TypemapOutputDirectory ) ;
81
143
82
- string abi = MonoAndroidHelper . ArchToAbi ( state . TargetArch ) ;
144
+ AddOutputTypeMaps ( tmg , state . TargetArch ) ;
145
+ }
146
+
147
+ void AddOutputTypeMaps ( TypeMapGenerator tmg , AndroidTargetArch arch )
148
+ {
149
+ string abi = MonoAndroidHelper . ArchToAbi ( arch ) ;
83
150
var items = new List < ITaskItem > ( ) ;
151
+
84
152
foreach ( string file in tmg . GeneratedBinaryTypeMaps ) {
85
153
var item = new TaskItem ( file ) ;
86
154
string fileName = Path . GetFileName ( file ) ;
@@ -90,6 +158,6 @@ void WriteTypeMappings (NativeCodeGenState state)
90
158
items . Add ( item ) ;
91
159
}
92
160
93
- GeneratedBinaryTypeMaps = items . ToArray ( ) ;
161
+ GeneratedBinaryTypeMaps = GeneratedBinaryTypeMaps . Concat ( items ) . ToArray ( ) ;
94
162
}
95
163
}
0 commit comments