Skip to content

Commit 281124f

Browse files
authored
More quick fixes for bugs related to #1250 (#1339)
* Resolve conflicts in native block wrapper names. Also remove nullable annotation from native code. It doesn't do anything and is sometimes invalid. * Use <> style imports for framework headers in ObjC native code Also, use #import instead of #include * Test framework header parser * More tests * Revert renaming of originalName. Add Func.useNameForLookup instead * nits
1 parent eeb5b0e commit 281124f

File tree

10 files changed

+105
-6
lines changed

10 files changed

+105
-6
lines changed

pkgs/ffigen/lib/src/code_generator/func.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class Func extends LookUpBinding {
4444
final bool exposeFunctionTypedefs;
4545
final bool isLeaf;
4646
final bool objCReturnsRetained;
47+
final bool useNameForLookup;
4748
final FfiNativeConfig ffiNativeConfig;
4849
late final String funcPointerName;
4950

@@ -64,6 +65,7 @@ class Func extends LookUpBinding {
6465
this.exposeFunctionTypedefs = false,
6566
this.isLeaf = false,
6667
this.objCReturnsRetained = false,
68+
this.useNameForLookup = false,
6769
super.isInternal,
6870
this.ffiNativeConfig = const FfiNativeConfig(enabled: false),
6971
}) : functionType = FunctionType(
@@ -92,6 +94,8 @@ class Func extends LookUpBinding {
9294
}
9395
}
9496

97+
String get _lookupName => useNameForLookup ? name : originalName;
98+
9599
@override
96100
BindingString toBindingString(Writer w) {
97101
final s = StringBuffer();
@@ -152,7 +156,7 @@ ${makeNativeAnnotation(
152156
w,
153157
nativeType: cType,
154158
dartName: nativeFuncName,
155-
nativeSymbolName: originalName,
159+
nativeSymbolName: _lookupName,
156160
isLeaf: isLeaf,
157161
)}
158162
external $ffiReturnType $nativeFuncName($ffiArgDeclString);
@@ -198,7 +202,7 @@ $dartReturnType $enclosingFuncName($dartArgDeclString) {
198202
// Write function pointer.
199203
s.write('''
200204
late final $funcPointerName = ${w.lookupFuncIdentifier}<
201-
${w.ffiLibraryPrefix}.NativeFunction<$cType>>('$originalName');
205+
${w.ffiLibraryPrefix}.NativeFunction<$cType>>('$_lookupName');
202206
late final $funcVarName = $funcPointerName.asFunction<$dartType>($isLeafString);
203207
204208
''');

pkgs/ffigen/lib/src/code_generator/objc_block.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ pointer.ref.invoke.cast<$natTrampFnType>().asFunction<$trampFuncFfiDartType>()(
238238
argsReceived.add(t.getNativeType(varName: argName));
239239
retains.add(t.generateRetain(argName) ?? argName);
240240
}
241-
final fnName = _wrapListenerBlock!.originalName;
241+
final fnName = _wrapListenerBlock!.name;
242242
final blockTypedef = w.objCLevelUniqueNamer.makeUnique('ListenerBlock');
243243

244244
final s = StringBuffer();
@@ -275,6 +275,7 @@ $blockTypedef $fnName($blockTypedef block) {
275275
objCReturnsRetained: true,
276276
isLeaf: true,
277277
isInternal: true,
278+
useNameForLookup: true,
278279
ffiNativeConfig: const FfiNativeConfig(enabled: true),
279280
)..addDependencies(dependencies);
280281
}

pkgs/ffigen/lib/src/code_generator/objc_nullable.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class ObjCNullable extends Type {
3838

3939
@override
4040
String getNativeType({String varName = ''}) =>
41-
'${child.getNativeType()} _Nullable $varName';
41+
child.getNativeType(varName: varName);
4242

4343
@override
4444
bool get sameFfiDartAndCType => child.sameFfiDartAndCType;

pkgs/ffigen/lib/src/code_generator/utils.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,18 @@ String findDart() {
140140
throw Exception(
141141
"Couldn't find Dart executable near ${Platform.resolvedExecutable}");
142142
}
143+
144+
/// Attempts to parse an absolute path to an ObjC framework header. Returns an
145+
/// importable path if successful, otherwise returns null.
146+
String? parseObjCFrameworkHeader(String path) {
147+
final match = _frameworkHeaderRegex.firstMatch(path);
148+
149+
if (match == null) {
150+
return null;
151+
}
152+
153+
return '${match[1]}/${match[2]}';
154+
}
155+
156+
final _frameworkHeaderRegex = RegExp(
157+
r'.*/Library(?:/.*/|/)Frameworks/([^/]+)\.framework(?:/.*/|/)Headers/(.*)');

pkgs/ffigen/lib/src/code_generator/writer.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,18 @@ class Writer {
396396
};
397397
}
398398

399+
static String _objcImport(String entryPoint, String outDir) {
400+
final frameworkHeader = parseObjCFrameworkHeader(entryPoint);
401+
402+
if (frameworkHeader == null) {
403+
// If it's not a framework header, use a relative import.
404+
return '#import "${p.relative(entryPoint, from: outDir)}"\n';
405+
}
406+
407+
// If it's a framework header, use a <> style import.
408+
return '#import <$frameworkHeader>';
409+
}
410+
399411
/// Writes the Objective C code needed for the bindings, if any. Returns null
400412
/// if there are no bindings that need generated ObjC code. This function does
401413
/// not generate the output file, but the [outFilename] does affect the
@@ -410,8 +422,7 @@ class Writer {
410422
''');
411423

412424
for (final entryPoint in nativeEntryPoints) {
413-
final path = p.relative(entryPoint, from: outDir);
414-
s.write('#include "$path"\n');
425+
s.write(_objcImport(entryPoint, outDir));
415426
}
416427

417428
var empty = true;

pkgs/ffigen/test/native_objc_test/block_config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ typedefs:
1919
- NullableObjectBlock
2020
- BlockBlock
2121
- ListenerBlock
22+
- ObjectListenerBlock
2223
- NullableListenerBlock
2324
- StructListenerBlock
2425
- NSStringListenerBlock

pkgs/ffigen/test/native_objc_test/block_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,17 @@ void main() {
189189
expect(isCalled, isTrue);
190190
});
191191

192+
test('Object listener block', () async {
193+
final hasRun = Completer<void>();
194+
final block = DartObjectListenerBlock.listener((DummyObject x) {
195+
expect(x, isNotNull);
196+
hasRun.complete();
197+
});
198+
199+
BlockTester.callObjectListener_(block);
200+
await hasRun.future;
201+
});
202+
192203
test('Nullable listener block', () async {
193204
final hasRun = Completer<void>();
194205
final block = DartNullableListenerBlock.listener((DummyObject? x) {

pkgs/ffigen/test/native_objc_test/block_test.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ typedef DummyObject* (^ObjectBlock)(DummyObject*);
3737
typedef DummyObject* _Nullable (^NullableObjectBlock)(DummyObject* _Nullable);
3838
typedef IntBlock (^BlockBlock)(IntBlock);
3939
typedef void (^ListenerBlock)(IntBlock);
40+
typedef void (^ObjectListenerBlock)(DummyObject*);
4041
typedef void (^NullableListenerBlock)(DummyObject* _Nullable);
4142
typedef void (^StructListenerBlock)(struct Vec2, Vec4, NSObject*);
4243
typedef void (^NSStringListenerBlock)(NSString*);
@@ -61,6 +62,7 @@ typedef void (^NoTrampolineListenerBlock)(int32_t, Vec4, const char*);
6162
+ (DummyObject*)callObjectBlock:(ObjectBlock)block NS_RETURNS_RETAINED;
6263
+ (nullable DummyObject*)callNullableObjectBlock:(NullableObjectBlock)block;
6364
+ (void)callListener:(ListenerBlock)block;
65+
+ (void)callObjectListener:(ObjectListenerBlock)block;
6466
+ (void)callNullableListener:(NullableListenerBlock)block;
6567
+ (void)callStructListener:(StructListenerBlock)block;
6668
+ (void)callNSStringListener:(NSStringListenerBlock)block x:(int32_t)x;

pkgs/ffigen/test/native_objc_test/block_test.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ + (NSThread*)callWithBlockOnNewThread:(ListenerBlock)block {
9494
object:block];
9595
}
9696

97+
+ (void)callObjectListener:(ObjectListenerBlock)block {
98+
block([DummyObject alloc]);
99+
}
100+
97101
+ (void)callNullableListener:(NullableListenerBlock)block {
98102
block(nil);
99103
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:ffigen/src/code_generator/utils.dart';
6+
import 'package:test/test.dart';
7+
8+
void main() {
9+
group('ObjC framework header test', () {
10+
test('parsing', () {
11+
expect(parseObjCFrameworkHeader(''), null);
12+
expect(parseObjCFrameworkHeader('/Foo/Bar.h'), null);
13+
expect(parseObjCFrameworkHeader('/Library/a/b/c/Headers/Bar.h'), null);
14+
expect(
15+
parseObjCFrameworkHeader(
16+
'/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/'
17+
'Library/Frameworks/AppKit.framework/Versions/C/Headers/NSMatrix.h'),
18+
'AppKit/NSMatrix.h');
19+
expect(
20+
parseObjCFrameworkHeader(
21+
'/System/Library/Frameworks/Photos.framework/Versions/Current/'
22+
'Headers/SomeHeader.h'),
23+
'Photos/SomeHeader.h');
24+
expect(
25+
parseObjCFrameworkHeader(
26+
'/Library/Frameworks/macFUSE.framework/Headers/macFUSE.h'),
27+
'macFUSE/macFUSE.h');
28+
expect(
29+
parseObjCFrameworkHeader(
30+
'/Library/Frameworks/Foo.framework/Headers/Bar.h'),
31+
'Foo/Bar.h');
32+
expect(
33+
parseObjCFrameworkHeader(
34+
'a/b/c/Library/Frameworks/Foo.framework/Headers/Bar.h'),
35+
'Foo/Bar.h');
36+
expect(
37+
parseObjCFrameworkHeader(
38+
'/Library/a/b/c/Frameworks/Foo.framework/Headers/Bar.h'),
39+
'Foo/Bar.h');
40+
expect(
41+
parseObjCFrameworkHeader(
42+
'/Library/Frameworks/Foo.framework/a/b/c/Headers/Bar.h'),
43+
'Foo/Bar.h');
44+
expect(
45+
parseObjCFrameworkHeader(
46+
'/Library/Frameworks/Foo.framework/Headers/a/b/c/Bar.h'),
47+
'Foo/a/b/c/Bar.h');
48+
});
49+
});
50+
}

0 commit comments

Comments
 (0)