Skip to content

Commit

Permalink
Handle dart typedefs in import/export of symbol files. (#1790)
Browse files Browse the repository at this point in the history
  • Loading branch information
mannprerak2 authored Dec 11, 2024
1 parent 2542108 commit f617a37
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 39 deletions.
1 change: 1 addition & 0 deletions pkgs/ffigen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Ensure that required symbols are available to FFI even when the final binary
is linked with `-dead_strip`.
- Handle dart typedefs in import/export of symbol files.

## 16.0.0

Expand Down
7 changes: 7 additions & 0 deletions pkgs/ffigen/example/shared_bindings/headers/a.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ enum A_Enum{
void a_func1();

void a_func2(struct BaseStruct2 s, union BaseUnion2 u, BaseTypedef2 t);

void a_func3(BaseNativeTypedef1 i);

void a_func4(BaseNativeTypedef2 i);

void a_func5(BaseNativeTypedef3 i);

4 changes: 4 additions & 0 deletions pkgs/ffigen/example/shared_bindings/headers/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ union BaseUnion2{

typedef struct BaseStruct1 BaseTypedef1;
typedef struct BaseStruct2 BaseTypedef2;
typedef int BaseNativeTypedef1;
typedef BaseNativeTypedef1 BaseNativeTypedef2;
typedef BaseNativeTypedef2 BaseNativeTypedef3;

enum BaseEnum{
BASE_ENUM_1,
Expand All @@ -29,3 +32,4 @@ enum BaseEnum{
#define BASE_MACRO_1 1;

void base_func1(BaseTypedef1 t1, BaseTypedef2 t2);

55 changes: 52 additions & 3 deletions pkgs/ffigen/example/shared_bindings/lib/generated/a_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,45 @@ class NativeLibraryA {
ffi.Void Function(BaseStruct2, BaseUnion2, BaseTypedef2)>>('a_func2');
late final _a_func2 = _a_func2Ptr
.asFunction<void Function(BaseStruct2, BaseUnion2, BaseTypedef2)>();

void a_func3(
int i,
) {
return _a_func3(
i,
);
}

late final _a_func3Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(BaseNativeTypedef1)>>(
'a_func3');
late final _a_func3 = _a_func3Ptr.asFunction<void Function(int)>();

void a_func4(
int i,
) {
return _a_func4(
i,
);
}

late final _a_func4Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(BaseNativeTypedef2)>>(
'a_func4');
late final _a_func4 = _a_func4Ptr.asFunction<void Function(int)>();

void a_func5(
int i,
) {
return _a_func5(
i,
);
}

late final _a_func5Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(BaseNativeTypedef3)>>(
'a_func5');
late final _a_func5 = _a_func5Ptr.asFunction<void Function(int)>();
}

final class BaseStruct1 extends ffi.Struct {
Expand All @@ -85,16 +124,26 @@ final class BaseUnion2 extends ffi.Union {
external int a;
}

typedef BaseTypedef1 = BaseStruct1;
typedef BaseTypedef2 = BaseStruct2;
typedef BaseNativeTypedef1 = ffi.Int;
typedef DartBaseNativeTypedef1 = int;
typedef BaseNativeTypedef2 = BaseNativeTypedef1;
typedef BaseNativeTypedef3 = BaseNativeTypedef2;

enum BaseEnum {
BASE_ENUM_1(0),
BASE_ENUM_2(1);

final int value;
const BaseEnum(this.value);
}

typedef BaseTypedef1 = BaseStruct1;
typedef BaseTypedef2 = BaseStruct2;
static BaseEnum fromValue(int value) => switch (value) {
0 => BASE_ENUM_1,
1 => BASE_ENUM_2,
_ => throw ArgumentError("Unknown value for BaseEnum: $value"),
};
}

final class A_Struct1 extends ffi.Struct {
@ffi.Int()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,48 @@ class NativeLibraryASharedB {
imp1.BaseTypedef2)>>('a_func2');
late final _a_func2 = _a_func2Ptr.asFunction<
void Function(imp1.BaseStruct2, imp1.BaseUnion2, imp1.BaseTypedef2)>();

void a_func3(
imp1.DartBaseNativeTypedef1 i,
) {
return _a_func3(
i,
);
}

late final _a_func3Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(imp1.BaseNativeTypedef1)>>(
'a_func3');
late final _a_func3 =
_a_func3Ptr.asFunction<void Function(imp1.DartBaseNativeTypedef1)>();

void a_func4(
imp1.DartBaseNativeTypedef1 i,
) {
return _a_func4(
i,
);
}

late final _a_func4Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(imp1.BaseNativeTypedef2)>>(
'a_func4');
late final _a_func4 =
_a_func4Ptr.asFunction<void Function(imp1.DartBaseNativeTypedef1)>();

void a_func5(
imp1.DartBaseNativeTypedef1 i,
) {
return _a_func5(
i,
);
}

late final _a_func5Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function(imp1.BaseNativeTypedef3)>>(
'a_func5');
late final _a_func5 =
_a_func5Ptr.asFunction<void Function(imp1.DartBaseNativeTypedef1)>();
}

final class A_Struct1 extends ffi.Struct {
Expand Down
16 changes: 13 additions & 3 deletions pkgs/ffigen/example/shared_bindings/lib/generated/base_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,25 @@ final class BaseUnion2 extends ffi.Union {
external int a;
}

typedef BaseTypedef1 = BaseStruct1;
typedef BaseTypedef2 = BaseStruct2;
typedef BaseNativeTypedef1 = ffi.Int;
typedef DartBaseNativeTypedef1 = int;
typedef BaseNativeTypedef2 = BaseNativeTypedef1;
typedef BaseNativeTypedef3 = BaseNativeTypedef2;

enum BaseEnum {
BASE_ENUM_1(0),
BASE_ENUM_2(1);

final int value;
const BaseEnum(this.value);
}

typedef BaseTypedef1 = BaseStruct1;
typedef BaseTypedef2 = BaseStruct2;
static BaseEnum fromValue(int value) => switch (value) {
0 => BASE_ENUM_1,
1 => BASE_ENUM_2,
_ => throw ArgumentError("Unknown value for BaseEnum: $value"),
};
}

const int BASE_MACRO_1 = 1;
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ files:
name: BaseUnion1
c:@U@BaseUnion2:
name: BaseUnion2
c:base.h@T@BaseNativeTypedef1:
name: BaseNativeTypedef1
dart-name: DartBaseNativeTypedef1
c:base.h@T@BaseNativeTypedef2:
name: BaseNativeTypedef2
dart-name: DartBaseNativeTypedef1
c:base.h@T@BaseNativeTypedef3:
name: BaseNativeTypedef3
dart-name: DartBaseNativeTypedef1
c:base.h@T@BaseTypedef1:
name: BaseTypedef1
c:base.h@T@BaseTypedef2:
Expand Down
72 changes: 50 additions & 22 deletions pkgs/ffigen/lib/src/code_generator/imports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,17 @@ class ImportedType extends Type {
final String nativeType;
final String? defaultValue;

ImportedType(this.libraryImport, this.cType, this.dartType, this.nativeType,
[this.defaultValue]);
/// Whether the [dartType] is an import from the [libraryImport].
final bool importedDartType;

ImportedType(
this.libraryImport,
this.cType,
this.dartType,
this.nativeType, {
this.defaultValue,
this.importedDartType = false,
});

@override
String getCType(Writer w) {
Expand All @@ -55,7 +64,14 @@ class ImportedType extends Type {
}

@override
String getFfiDartType(Writer w) => cType == dartType ? getCType(w) : dartType;
String getFfiDartType(Writer w) {
if (importedDartType) {
w.markImportUsed(libraryImport);
return '${libraryImport.prefix}.$dartType';
} else {
return cType == dartType ? getCType(w) : dartType;
}
}

@override
String getNativeType({String varName = ''}) => '$nativeType $varName';
Expand Down Expand Up @@ -107,30 +123,42 @@ final self = LibraryImport('self', '');

final voidType = ImportedType(ffiImport, 'Void', 'void', 'void');

final unsignedCharType =
ImportedType(ffiImport, 'UnsignedChar', 'int', 'unsigned char', '0');
final unsignedCharType = ImportedType(
ffiImport, 'UnsignedChar', 'int', 'unsigned char',
defaultValue: '0');
final signedCharType =
ImportedType(ffiImport, 'SignedChar', 'int', 'char', '0');
final charType = ImportedType(ffiImport, 'Char', 'int', 'char', '0');
final unsignedShortType =
ImportedType(ffiImport, 'UnsignedShort', 'int', 'unsigned short', '0');
final shortType = ImportedType(ffiImport, 'Short', 'int', 'short', '0');
final unsignedIntType =
ImportedType(ffiImport, 'UnsignedInt', 'int', 'unsigned', '0');
final intType = ImportedType(ffiImport, 'Int', 'int', 'int', '0');
final unsignedLongType =
ImportedType(ffiImport, 'UnsignedLong', 'int', 'unsigned long', '0');
final longType = ImportedType(ffiImport, 'Long', 'int', 'long', '0');
ImportedType(ffiImport, 'SignedChar', 'int', 'char', defaultValue: '0');
final charType =
ImportedType(ffiImport, 'Char', 'int', 'char', defaultValue: '0');
final unsignedShortType = ImportedType(
ffiImport, 'UnsignedShort', 'int', 'unsigned short',
defaultValue: '0');
final shortType =
ImportedType(ffiImport, 'Short', 'int', 'short', defaultValue: '0');
final unsignedIntType = ImportedType(
ffiImport, 'UnsignedInt', 'int', 'unsigned',
defaultValue: '0');
final intType = ImportedType(ffiImport, 'Int', 'int', 'int', defaultValue: '0');
final unsignedLongType = ImportedType(
ffiImport, 'UnsignedLong', 'int', 'unsigned long',
defaultValue: '0');
final longType =
ImportedType(ffiImport, 'Long', 'int', 'long', defaultValue: '0');
final unsignedLongLongType = ImportedType(
ffiImport, 'UnsignedLongLong', 'int', 'unsigned long long', '0');
ffiImport, 'UnsignedLongLong', 'int', 'unsigned long long',
defaultValue: '0');
final longLongType =
ImportedType(ffiImport, 'LongLong', 'int', 'long long', '0');
ImportedType(ffiImport, 'LongLong', 'int', 'long long', defaultValue: '0');

final floatType = ImportedType(ffiImport, 'Float', 'double', 'float', '0.0');
final doubleType = ImportedType(ffiImport, 'Double', 'double', 'double', '0.0');
final floatType =
ImportedType(ffiImport, 'Float', 'double', 'float', defaultValue: '0.0');
final doubleType =
ImportedType(ffiImport, 'Double', 'double', 'double', defaultValue: '0.0');

final sizeType = ImportedType(ffiImport, 'Size', 'int', 'size_t', '0');
final wCharType = ImportedType(ffiImport, 'WChar', 'int', 'wchar_t', '0');
final sizeType =
ImportedType(ffiImport, 'Size', 'int', 'size_t', defaultValue: '0');
final wCharType =
ImportedType(ffiImport, 'WChar', 'int', 'wchar_t', defaultValue: '0');

final objCObjectType =
ImportedType(objcPkgImport, 'ObjCObject', 'ObjCObject', 'void');
Expand Down
16 changes: 8 additions & 8 deletions pkgs/ffigen/lib/src/code_generator/typealias.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import 'writer.dart';
class Typealias extends BindingType {
final Type type;
String? _ffiDartAliasName;
String? _dartAliasName;
String? dartAliasName;

/// Creates a Typealias.
///
Expand Down Expand Up @@ -75,7 +75,7 @@ class Typealias extends BindingType {
bool genFfiDartType = false,
super.isInternal,
}) : _ffiDartAliasName = genFfiDartType ? 'Dart$name' : null,
_dartAliasName =
dartAliasName =
(!genFfiDartType && type is! Typealias && !type.sameDartAndCType)
? 'Dart$name'
: null,
Expand All @@ -95,8 +95,8 @@ class Typealias extends BindingType {
if (_ffiDartAliasName != null) {
_ffiDartAliasName = w.topLevelUniqueNamer.makeUnique(_ffiDartAliasName!);
}
if (_dartAliasName != null) {
_dartAliasName = w.topLevelUniqueNamer.makeUnique(_dartAliasName!);
if (dartAliasName != null) {
dartAliasName = w.topLevelUniqueNamer.makeUnique(dartAliasName!);
}

final sb = StringBuffer();
Expand All @@ -107,8 +107,8 @@ class Typealias extends BindingType {
if (_ffiDartAliasName != null) {
sb.write('typedef $_ffiDartAliasName = ${type.getFfiDartType(w)};\n');
}
if (_dartAliasName != null) {
sb.write('typedef $_dartAliasName = ${type.getDartType(w)};\n');
if (dartAliasName != null) {
sb.write('typedef $dartAliasName = ${type.getDartType(w)};\n');
}
return BindingString(
type: BindingStringType.typeDef, string: sb.toString());
Expand Down Expand Up @@ -142,8 +142,8 @@ class Typealias extends BindingType {
@override
String getDartType(Writer w) {
if (generateBindings) {
if (_dartAliasName != null) {
return _dartAliasName!;
if (dartAliasName != null) {
return dartAliasName!;
} else if (type.sameDartAndCType) {
return getFfiDartType(w);
}
Expand Down
15 changes: 14 additions & 1 deletion pkgs/ffigen/lib/src/code_generator/writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -390,13 +390,26 @@ class Writer {
strings.ffiNative: usesFfiNative,
},
strings.symbols: {
for (final b in bindings) b.usr: {strings.name: b.name},
for (final b in bindings) b.usr: _makeSymbolMapValue(b),
},
},
},
};
}

Map<String, String> _makeSymbolMapValue(Binding b) {
final dartName = b is Typealias ? getTypedefDartAliasName(b) : null;
return {
strings.name: b.name,
if (dartName != null) strings.dartName: dartName,
};
}

String? getTypedefDartAliasName(Type b) {
if (b is! Typealias) return null;
return b.dartAliasName ?? getTypedefDartAliasName(b.type);
}

static String _objcImport(String entryPoint, String outDir) {
final frameworkHeader = parseObjCFrameworkHeader(entryPoint);

Expand Down
6 changes: 4 additions & 2 deletions pkgs/ffigen/lib/src/config_provider/spec_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ void loadImportedTypes(YamlMap fileConfig,
for (final key in symbols.keys) {
final usr = key as String;
final value = symbols[usr]! as YamlMap;
final name = value['name'] as String;
usrTypeMappings[usr] = ImportedType(libraryImport, name, name, name);
final name = value[strings.name] as String;
final dartName = (value[strings.dartName] as String?) ?? name;
usrTypeMappings[usr] = ImportedType(libraryImport, name, dartName, name,
importedDartType: true);
}
}

Expand Down
Loading

0 comments on commit f617a37

Please sign in to comment.