[ffigen] Move ObjCBuiltInFunctions to its own file and its singleton to data.dart (#325)
diff --git a/pkgs/ffigen/lib/src/code_generator.dart b/pkgs/ffigen/lib/src/code_generator.dart index a0c5d7e..f599c7b 100644 --- a/pkgs/ffigen/lib/src/code_generator.dart +++ b/pkgs/ffigen/lib/src/code_generator.dart
@@ -16,6 +16,7 @@ export 'code_generator/imports.dart'; export 'code_generator/library.dart'; export 'code_generator/native_type.dart'; +export 'code_generator/objc_built_in_functions.dart'; export 'code_generator/objc_interface.dart'; export 'code_generator/pointer.dart'; export 'code_generator/struct.dart';
diff --git a/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart b/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart new file mode 100644 index 0000000..3c170c0 --- /dev/null +++ b/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart
@@ -0,0 +1,112 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:ffigen/src/code_generator.dart'; + +import 'writer.dart'; + +/// Built in functions used by the Objective C bindings. +class ObjCBuiltInFunctions { + late final _registerNameFunc = Func( + name: '_sel_registerName', + originalName: 'sel_registerName', + returnType: PointerType(objCSelType), + parameters: [Parameter(name: 'str', type: PointerType(charType))], + isInternal: true, + ); + late final String registerName; + + late final _getClassFunc = Func( + name: '_objc_getClass', + originalName: 'objc_getClass', + returnType: PointerType(objCObjectType), + parameters: [Parameter(name: 'str', type: PointerType(charType))], + isInternal: true, + ); + late final String getClass; + + // We need to load a separate instance of objc_msgSend for each signature. + final _msgSendFuncs = <String, Func>{}; + Func getMsgSendFunc(Type returnType, List<ObjCMethodParam> params) { + // TODO(#279): These keys don't dedupe sufficiently. + var key = returnType.hashCode.toRadixString(36); + for (final p in params) { + key += ' ' + p.type.hashCode.toRadixString(36); + } + _msgSendFuncs[key] ??= Func( + name: '_objc_msgSend_${_msgSendFuncs.length}', + originalName: 'objc_msgSend', + returnType: returnType, + parameters: [ + Parameter(name: 'obj', type: PointerType(objCObjectType)), + Parameter(name: 'sel', type: PointerType(objCSelType)), + for (final p in params) Parameter(name: p.name, type: p.type), + ], + isInternal: true, + ); + return _msgSendFuncs[key]!; + } + + bool utilsExist = false; + void ensureUtilsExist(Writer w, StringBuffer s) { + if (utilsExist) return; + utilsExist = true; + + registerName = w.topLevelUniqueNamer.makeUnique('_registerName'); + final selType = _registerNameFunc.functionType.returnType.getCType(w); + s.write('\n$selType $registerName(${w.className} _lib, String name) {\n'); + s.write(' final cstr = name.toNativeUtf8();\n'); + s.write(' final sel = _lib.${_registerNameFunc.name}(cstr.cast());\n'); + s.write(' ${w.ffiPkgLibraryPrefix}.calloc.free(cstr);\n'); + s.write(' return sel;\n'); + s.write('}\n'); + + getClass = w.topLevelUniqueNamer.makeUnique('_getClass'); + final objType = _getClassFunc.functionType.returnType.getCType(w); + s.write('\n$objType $getClass(${w.className} _lib, String name) {\n'); + s.write(' final cstr = name.toNativeUtf8();\n'); + s.write(' final clazz = _lib.${_getClassFunc.name}(cstr.cast());\n'); + s.write(' ${w.ffiPkgLibraryPrefix}.calloc.free(cstr);\n'); + s.write(' return clazz;\n'); + s.write('}\n'); + + s.write('\nclass _ObjCWrapper {\n'); + s.write(' final $objType _id;\n'); + s.write(' final ${w.className} _lib;\n'); + s.write(' _ObjCWrapper._(this._id, this._lib);\n'); + s.write('}\n'); + } + + void addDependencies(Set<Binding> dependencies) { + _registerNameFunc.addDependencies(dependencies); + _getClassFunc.addDependencies(dependencies); + for (final func in _msgSendFuncs.values) { + func.addDependencies(dependencies); + } + } + + void generateNSStringUtils(Writer w, StringBuffer s) { + // Generate a constructor that wraps stringWithCString. + s.write(' factory NSString(${w.className} _lib, String str) {\n'); + s.write(' final cstr = str.toNativeUtf8();\n'); + s.write(' final nsstr = stringWithCString_encoding(' + '_lib, cstr.cast(), 4 /* UTF8 */);\n'); + s.write(' ${w.ffiPkgLibraryPrefix}.calloc.free(cstr);\n'); + s.write(' return nsstr;\n'); + s.write(' }\n\n'); + + // Generate a toString method that wraps UTF8String. + s.write(' @override\n'); + s.write(' String toString() => UTF8String().cast<' + '${w.ffiPkgLibraryPrefix}.Utf8>().toDartString();\n\n'); + } + + void generateStringUtils(Writer w, StringBuffer s) { + // Generate an extension on String to convert to NSString + s.write('extension StringToNSString on String {\n'); + s.write(' NSString toNSString(${w.className} lib) => ' + 'NSString(lib, this);\n'); + s.write('}\n\n'); + } +}
diff --git a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart index 4b59379..ed9e1c3 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
@@ -30,112 +30,6 @@ 'superclass', }; -class _ObjCBuiltInFunctions { - late final _registerNameFunc = Func( - name: '_sel_registerName', - originalName: 'sel_registerName', - returnType: PointerType(objCSelType), - parameters: [Parameter(name: 'str', type: PointerType(charType))], - isInternal: true, - ); - late final String registerName; - - late final _getClassFunc = Func( - name: '_objc_getClass', - originalName: 'objc_getClass', - returnType: PointerType(objCObjectType), - parameters: [Parameter(name: 'str', type: PointerType(charType))], - isInternal: true, - ); - late final String getClass; - - // We need to load a separate instance of objc_msgSend for each signature. - final _msgSendFuncs = <String, Func>{}; - Func getMsgSendFunc(Type returnType, List<ObjCMethodParam> params) { - // TODO(#279): These keys don't dedupe sufficiently. - var key = returnType.hashCode.toRadixString(36); - for (final p in params) { - key += ' ' + p.type.hashCode.toRadixString(36); - } - _msgSendFuncs[key] ??= Func( - name: '_objc_msgSend_${_msgSendFuncs.length}', - originalName: 'objc_msgSend', - returnType: returnType, - parameters: [ - Parameter(name: 'obj', type: PointerType(objCObjectType)), - Parameter(name: 'sel', type: PointerType(objCSelType)), - for (final p in params) Parameter(name: p.name, type: p.type), - ], - isInternal: true, - ); - return _msgSendFuncs[key]!; - } - - bool utilsExist = false; - void ensureUtilsExist(Writer w, StringBuffer s) { - if (utilsExist) return; - utilsExist = true; - - registerName = w.topLevelUniqueNamer.makeUnique('_registerName'); - final selType = _registerNameFunc.functionType.returnType.getCType(w); - s.write('\n$selType $registerName(${w.className} _lib, String name) {\n'); - s.write(' final cstr = name.toNativeUtf8();\n'); - s.write(' final sel = _lib.${_registerNameFunc.name}(cstr.cast());\n'); - s.write(' ${w.ffiPkgLibraryPrefix}.calloc.free(cstr);\n'); - s.write(' return sel;\n'); - s.write('}\n'); - - getClass = w.topLevelUniqueNamer.makeUnique('_getClass'); - final objType = _getClassFunc.functionType.returnType.getCType(w); - s.write('\n$objType $getClass(${w.className} _lib, String name) {\n'); - s.write(' final cstr = name.toNativeUtf8();\n'); - s.write(' final clazz = _lib.${_getClassFunc.name}(cstr.cast());\n'); - s.write(' ${w.ffiPkgLibraryPrefix}.calloc.free(cstr);\n'); - s.write(' return clazz;\n'); - s.write('}\n'); - - s.write('\nclass _ObjCWrapper {\n'); - s.write(' final $objType _id;\n'); - s.write(' final ${w.className} _lib;\n'); - s.write(' _ObjCWrapper._(this._id, this._lib);\n'); - s.write('}\n'); - } - - void addDependencies(Set<Binding> dependencies) { - _registerNameFunc.addDependencies(dependencies); - _getClassFunc.addDependencies(dependencies); - for (final func in _msgSendFuncs.values) { - func.addDependencies(dependencies); - } - } - - void generateNSStringUtils(Writer w, StringBuffer s) { - // Generate a constructor that wraps stringWithCString. - s.write(' factory NSString(${w.className} _lib, String str) {\n'); - s.write(' final cstr = str.toNativeUtf8();\n'); - s.write(' final nsstr = stringWithCString_encoding(' - '_lib, cstr.cast(), 4 /* UTF8 */);\n'); - s.write(' ${w.ffiPkgLibraryPrefix}.calloc.free(cstr);\n'); - s.write(' return nsstr;\n'); - s.write(' }\n\n'); - - // Generate a toString method that wraps UTF8String. - s.write(' @override\n'); - s.write(' String toString() => UTF8String().cast<' - '${w.ffiPkgLibraryPrefix}.Utf8>().toDartString();\n\n'); - } - - void generateStringUtils(Writer w, StringBuffer s) { - // Generate an extension on String to convert to NSString - s.write('extension StringToNSString on String {\n'); - s.write(' NSString toNSString(${w.className} lib) => ' - 'NSString(lib, this);\n'); - s.write('}\n\n'); - } -} - -final _builtInFunctions = _ObjCBuiltInFunctions(); - class ObjCInterface extends BindingType { ObjCInterface? superType; final methods = <ObjCMethod>[]; @@ -148,11 +42,14 @@ // methods list. final classMethods = <String, ObjCMethod>{}; + final ObjCBuiltInFunctions builtInFunctions; + ObjCInterface({ String? usr, required String originalName, required String name, String? dartDoc, + required this.builtInFunctions, }) : super( usr: usr, originalName: originalName, @@ -184,7 +81,7 @@ final uniqueNamer = UniqueNamer({name}); final natLib = w.className; - _builtInFunctions.ensureUtilsExist(w, s); + builtInFunctions.ensureUtilsExist(w, s); final objType = PointerType(objCObjectType).getCType(w); final selType = PointerType(objCSelType).getCType(w); @@ -204,7 +101,7 @@ s.write(' }\n\n'); if (isNSString) { - _builtInFunctions.generateNSStringUtils(w, s); + builtInFunctions.generateNSStringUtils(w, s); } // Methods. @@ -273,10 +170,10 @@ // Implementation. if (isStatic) { s.write(' $classObject ??= ' - '${_builtInFunctions.getClass}(_lib, "$originalName");\n'); + '${builtInFunctions.getClass}(_lib, "$originalName");\n'); } s.write(' $selName ??= ' - '${_builtInFunctions.registerName}(_lib, "${m.originalName}");\n'); + '${builtInFunctions.registerName}(_lib, "${m.originalName}");\n'); final convertReturn = m.kind != ObjCMethodKind.propertySetter && _needsConverting(returnType); @@ -301,7 +198,7 @@ s.write('}\n\n'); if (isNSString) { - _builtInFunctions.generateStringUtils(w, s); + builtInFunctions.generateStringUtils(w, s); } return BindingString( @@ -325,10 +222,10 @@ } for (final m in methods) { - m.addDependencies(dependencies); + m.addDependencies(dependencies, builtInFunctions); } - _builtInFunctions.addDependencies(dependencies); + builtInFunctions.addDependencies(dependencies); } void _filterPropertyMethods() { @@ -469,13 +366,14 @@ kind == ObjCMethodKind.propertyGetter || kind == ObjCMethodKind.propertySetter; - void addDependencies(Set<Binding> dependencies) { + void addDependencies( + Set<Binding> dependencies, ObjCBuiltInFunctions builtInFunctions) { returnType ??= NativeType(SupportedNativeType.Void); returnType!.addDependencies(dependencies); for (final p in params) { p.type.addDependencies(dependencies); } - msgSend = _builtInFunctions.getMsgSendFunc(returnType!, params); + msgSend = builtInFunctions.getMsgSendFunc(returnType!, params); } String _getDartMethodName(UniqueNamer uniqueNamer) {
diff --git a/pkgs/ffigen/lib/src/header_parser/data.dart b/pkgs/ffigen/lib/src/header_parser/data.dart index ac16572..1381fd3 100644 --- a/pkgs/ffigen/lib/src/header_parser/data.dart +++ b/pkgs/ffigen/lib/src/header_parser/data.dart
@@ -4,7 +4,8 @@ import 'dart:ffi'; -import 'package:ffigen/src/code_generator.dart' show Constant; +import 'package:ffigen/src/code_generator.dart' + show Constant, ObjCBuiltInFunctions; import 'package:ffigen/src/config_provider.dart' show Config; import 'clang_bindings/clang_bindings.dart' show Clang; @@ -36,6 +37,10 @@ List<Constant> get unnamedEnumConstants => _unnamedEnumConstants; List<Constant> _unnamedEnumConstants = []; +/// Built in functions used by the Objective C bindings. +ObjCBuiltInFunctions get objCBuiltInFunctions => _objCBuiltInFunctions; +late ObjCBuiltInFunctions _objCBuiltInFunctions; + void initializeGlobals({required Config config}) { _config = config; _clang = Clang(DynamicLibrary.open(config.libclangDylib)); @@ -43,4 +48,5 @@ _savedMacros = {}; _unnamedEnumConstants = []; _bindingsIndex = BindingsIndex(); + _objCBuiltInFunctions = ObjCBuiltInFunctions(); }
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart index 26dd1b3..d90f56c 100644 --- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart +++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart
@@ -45,6 +45,7 @@ usr: itfUsr, originalName: name, name: name, // TODO(#279): config.interfaceDecl.renameUsingConfig(name), dartDoc: getCursorDocComment(cursor), + builtInFunctions: objCBuiltInFunctions, ); }