dart-lang / native

Dart packages related to FFI and native assets bundling.
BSD 3-Clause "New" or "Revised" License
82 stars 27 forks source link

[ffigen] Generate `ResourceIdentifier`s for Objective-C #1099

Open dcharkes opened 3 weeks ago

dcharkes commented 3 weeks ago

For tree-shaking we want to generate ResourceIdentifier annotations.

For C:

For JNIgen:

Probably for Objective-C (and Swift?) we could or should do something similar. The idea for C code is to compile to a static lib with all symbols in build.dart and then call the native linker in link.dart and pass the exact list of C symbols to keep based on what @Natives (annotated with @ResourceIdentifier) are reachable after TFA. Would a similar approach work for Objective-C @liamappelbe?

I presume that for the actual classes in Objective-C we might need something more similar to JNIgen, where we generate @ResourceIdentifiers for the classes and instance methods.

Same questions to answer here:

liamappelbe commented 3 weeks ago

Tree shaking the ObjC library based on how it's used from Dart? Yeah, probably need to use the same approach as JNIgen. There are only a few @Native functions used by the ObjC bindings (objc_msgSend etc), and they're all always used and always available in the process itself. Tree shaking the methods would require a bit more info as you say.

Looking at the dylib for one of the ObjC tests in ffigen, we can see entries for the class and the methods. In this case there's a StringUtil class with a single strConcat:with: method:

liama-macbookpro:ffigen liama$ nm /Users/liama/dev/native/pkgs/ffigen/test/native_objc_test/string_test.dylib 
0000000000003f10 t +[StringUtil strConcat:with:]
                 U _OBJC_CLASS_$_NSObject
00000000000080c8 S _OBJC_CLASS_$_StringUtil
                 U _OBJC_METACLASS_$_NSObject
00000000000080a0 S _OBJC_METACLASS_$_StringUtil
0000000000003f48 s __OBJC_$_CLASS_METHODS_StringUtil
0000000000008048 s __OBJC_CLASS_RO_$_StringUtil
0000000000008000 s __OBJC_METACLASS_RO_$_StringUtil
                 U __objc_empty_cache
                 U _objc_msgSend

So it should be fairly straightforward to filter these methods and classes based on the @ResourceIdentifier.

What do we need from the resource.json format?

The class, the methods. Also, whether or not the method is static, since that affects the name in the dylib (note the + prefix, which would be a - if this was an instance method).

Probably also the class's super class, so that we retain the super class of any used class. Do we need to include the method's argument types so that we retain those classes too? I guess for both of these cases we could just add the super class/argument class as another ordinary "please retain this class" entry, rather than as metadata on the parent class.

What does the @ResourceIdentifier annotation look like? Due to renaming It would be very brittle to try to infer the ObjC names for the classes and methods based on the Dart name. Do we have the option of passing the true names to the annotation?

dcharkes commented 3 weeks ago

What does the @ResourceIdentifier annotation look like? Due to renaming It would be very brittle to try to infer the ObjC names for the classes and methods based on the Dart name. Do we have the option of passing the true names to the annotation?

That's a great point! Yes, there's a free-form Object? metadata field. https://pub.dev/documentation/meta/latest/meta/ResourceIdentifier-class.html

So we could generate something like:

@ResourceIdentifier({
  'ffigen': true,
  'objective_c': true,
  'objective_c_class' : 'OriginalObjectiveCClassName',
  'objective_c_method' : 'OriginalObjectiveCMethodName',
  'objective_c_method_static' : true,
  'objective_c_super_class' : 'OriginalObjectiveCClassName',
})