[ffigen] Added support for marking functions as Leaf. (#252)
* Add support for specifying leaf functions.
* Remove folder debug_generated to prevent warning when publishing.
* Add an FAQ for explaining generated logs.
diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md
index 02b880e..9cdf028 100644
--- a/pkgs/ffigen/CHANGELOG.md
+++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 4.1.0
+- Add config key `functions -> leaf` for specifying `isLeaf:true` for functions.
+
# 4.0.0
- Release for Dart SDK `>=2.14`.
diff --git a/pkgs/ffigen/README.md b/pkgs/ffigen/README.md
index e89ceb2..0cf4247 100644
--- a/pkgs/ffigen/README.md
+++ b/pkgs/ffigen/README.md
@@ -292,6 +292,28 @@
</td>
</tr>
<tr>
+ <td>functions -> leaf</td>
+ <td>Set isLeaf:true for functions.<br>
+ <b>Default: all functions are excluded.</b>
+ </td>
+ <td>
+
+```yaml
+functions:
+ leaf:
+ include:
+ # Match function name.
+ - 'myFunc'
+ # Do this to set isLeaf:true for all functions.
+ - '.*'
+ exclude:
+ # If you only use exclude, then everything
+ # not excluded is generated.
+ - 'dispose'
+```
+ </td>
+ </tr>
+ <tr>
<td>structs -> pack</td>
<td>Override the @Packed(X) annotation for generated structs.<br><br>
<i>Options - none, 1, 2, 4, 8, 16</i><br>
@@ -593,6 +615,25 @@
### Why are some typedefs not generated?
The following typedefs are not generated -
-- They are not referred to anywhere in the included declarations.
-- They refer to a struct/union having the same name as itself.
-- They refer to a boolean, enum, inline array, Handle or any unsupported type.
+ - They are not referred to anywhere in the included declarations.
+ - They refer to a struct/union having the same name as itself.
+ - They refer to a boolean, enum, inline array, Handle or any unsupported type.
+
+### What are these logs generated by ffigen and how to fix them?
+
+Ffigen can sometimes generate a lot of logs, especially when it's parsing a lot of code.
+ - `SEVERE` logs are something you *definitely need to address*. They can be
+ caused due to syntax errors, or more generally missing header files
+ (which need to be specified using `compiler-opts` in config)
+ - `WARNING` logs are something *you can ignore*, but should probably look into.
+ These are mostly indications of declarations ffigen couldn't generate due
+ to limitations of dart:ffi, private declarations (which can be resolved
+ by renaming them via ffigen config) or other minor issues in the config
+ file itself.
+ - Everything else can be safely ignored. It's purpose is to simply
+ let you know what ffigen is doing.
+ - The verbosity of the logs can be changed by adding a flag with
+ the log level. E.g - `dart run ffigen --verbose <level>`.
+ Level options are - `[all, fine, info (default), warning, severe]`.
+ The `all` and `fine` will print a ton of logs are meant for debugging
+ purposes only.
diff --git a/pkgs/ffigen/lib/src/code_generator/func.dart b/pkgs/ffigen/lib/src/code_generator/func.dart
index e779c77..425ee47 100644
--- a/pkgs/ffigen/lib/src/code_generator/func.dart
+++ b/pkgs/ffigen/lib/src/code_generator/func.dart
@@ -32,6 +32,7 @@
final FunctionType functionType;
final bool exposeSymbolAddress;
final bool exposeFunctionTypedefs;
+ final bool isLeaf;
/// Contains typealias for function type if [exposeFunctionTypedefs] is true.
Typealias? _exposedCFunctionTypealias, _exposedDartFunctionTypealias;
@@ -47,6 +48,7 @@
List<Parameter>? parameters,
this.exposeSymbolAddress = false,
this.exposeFunctionTypedefs = false,
+ this.isLeaf = false,
}) : functionType = FunctionType(
returnType: returnType,
parameters: parameters ?? const [],
@@ -152,8 +154,9 @@
// Write function pointer.
s.write(
"late final $funcPointerName = ${w.lookupFuncIdentifier}<${w.ffiLibraryPrefix}.NativeFunction<$cType>>('$originalName');\n");
+ final isLeafString = isLeaf ? 'isLeaf:true' : '';
s.write(
- 'late final $funcVarName = $funcPointerName.asFunction<$dartType>();\n\n');
+ 'late final $funcVarName = $funcPointerName.asFunction<$dartType>($isLeafString);\n\n');
return BindingString(type: BindingStringType.func, string: s.toString());
}
diff --git a/pkgs/ffigen/lib/src/config_provider/config.dart b/pkgs/ffigen/lib/src/config_provider/config.dart
index 7d8c261..88d5d8d 100644
--- a/pkgs/ffigen/lib/src/config_provider/config.dart
+++ b/pkgs/ffigen/lib/src/config_provider/config.dart
@@ -119,6 +119,9 @@
Includer get exposeFunctionTypedefs => _exposeFunctionTypedefs;
late Includer _exposeFunctionTypedefs;
+ Includer get leafFunctions => _leafFunctions;
+ late Includer _leafFunctions;
+
Config._();
/// Create config from Yaml map.
@@ -416,6 +419,14 @@
extractedResult: (dynamic result) =>
_exposeFunctionTypedefs = result as Includer,
),
+ [strings.functions, strings.leafFunctions]: Specification<Includer>(
+ requirement: Requirement.no,
+ validator: leafFunctionValidator,
+ extractor: leafFunctionExtractor,
+ defaultValue: () => Includer.excludeByDefault(),
+ extractedResult: (dynamic result) =>
+ _leafFunctions = result as Includer,
+ ),
};
}
}
diff --git a/pkgs/ffigen/lib/src/config_provider/spec_utils.dart b/pkgs/ffigen/lib/src/config_provider/spec_utils.dart
index 5acd29e..ad76cc9 100644
--- a/pkgs/ffigen/lib/src/config_provider/spec_utils.dart
+++ b/pkgs/ffigen/lib/src/config_provider/spec_utils.dart
@@ -592,6 +592,31 @@
return _result;
}
+Includer leafFunctionExtractor(dynamic value) =>
+ _extractIncluderFromYaml(value);
+
+bool leafFunctionValidator(List<String> name, dynamic value) {
+ var _result = true;
+
+ if (!checkType<YamlMap>(name, value)) {
+ _result = false;
+ } else {
+ final mp = value as YamlMap;
+ for (final key in mp.keys) {
+ if (key == strings.include || key == strings.exclude) {
+ if (!checkType<YamlList>([...name, key as String], value[key])) {
+ _result = false;
+ }
+ } else {
+ _logger.severe("Unknown subkey '$key' in '$name'.");
+ _result = false;
+ }
+ }
+ }
+
+ return _result;
+}
+
SupportedNativeType nativeSupportedType(int value, {bool signed = true}) {
switch (value) {
case 1:
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
index 7a0bb20..41d877c 100644
--- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
@@ -80,6 +80,7 @@
config.functionDecl.shouldIncludeSymbolAddress(funcName),
exposeFunctionTypedefs:
config.exposeFunctionTypedefs.shouldInclude(funcName),
+ isLeaf: config.leafFunctions.shouldInclude(funcName),
);
bindingsIndex.addFuncToSeen(funcUsr, _stack.top.func!);
} else if (bindingsIndex.isSeenFunc(funcUsr)) {
diff --git a/pkgs/ffigen/lib/src/strings.dart b/pkgs/ffigen/lib/src/strings.dart
index 84e767c..5ae3e35 100644
--- a/pkgs/ffigen/lib/src/strings.dart
+++ b/pkgs/ffigen/lib/src/strings.dart
@@ -62,6 +62,7 @@
// Nested under `functions`
const exposeFunctionTypedefs = 'expose-typedefs';
+const leafFunctions = 'leaf';
const dependencyOnly = 'dependency-only';
// Values for `compoundDependencies`.
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml
index ae3782f..f4e7135 100644
--- a/pkgs/ffigen/pubspec.yaml
+++ b/pkgs/ffigen/pubspec.yaml
@@ -3,7 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
name: ffigen
-version: 4.0.0
+version: 4.1.0
homepage: https://github.com/dart-lang/ffigen
description: Generator for FFI bindings, using LibClang to parse C header files.
diff --git a/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
index 5d7f4c9..34905a4 100644
--- a/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
+++ b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
@@ -67,6 +67,22 @@
),
),
),
+ Func(
+ isLeaf: true,
+ name: 'leafFunc',
+ dartDoc: 'A function with isLeaf: true',
+ parameters: [
+ Parameter(
+ name: 'a',
+ type: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ ],
+ returnType: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
],
);
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart
index 2a7dba5..ada968c 100644
--- a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart
+++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart
@@ -60,4 +60,18 @@
late final _withPointerParam = _withPointerParamPtr.asFunction<
ffi.Pointer<ffi.Double> Function(
ffi.Pointer<ffi.Int32>, ffi.Pointer<ffi.Pointer<ffi.Uint8>>)>();
+
+ /// A function with isLeaf: true
+ int leafFunc(
+ int a,
+ ) {
+ return _leafFunc(
+ a,
+ );
+ }
+
+ late final _leafFuncPtr =
+ _lookup<ffi.NativeFunction<ffi.Int32 Function(ffi.Int32)>>('leafFunc');
+ late final _leafFunc =
+ _leafFuncPtr.asFunction<int Function(int)>(isLeaf: true);
}
diff --git a/pkgs/ffigen/test/debug_generated/README.md b/pkgs/ffigen/test/debug_generated/README.md
deleted file mode 100644
index f8fe72f..0000000
--- a/pkgs/ffigen/test/debug_generated/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-This folder is used in tests.
-These files are deleted if tests are successful, but
-will contain debug files from failed tests.
diff --git a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_functions_bindings.dart b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_functions_bindings.dart
index a5e3276..d42ec32 100644
--- a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_functions_bindings.dart
+++ b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_functions_bindings.dart
@@ -27,7 +27,7 @@
late final _func1Ptr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('func1');
- late final _func1 = _func1Ptr.asFunction<void Function()>();
+ late final _func1 = _func1Ptr.asFunction<void Function()>(isLeaf: true);
int func2(
int arg0,
diff --git a/pkgs/ffigen/test/header_parser_tests/functions_test.dart b/pkgs/ffigen/test/header_parser_tests/functions_test.dart
index 87a8642..7b07562 100644
--- a/pkgs/ffigen/test/header_parser_tests/functions_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/functions_test.dart
@@ -34,6 +34,9 @@
${strings.include}:
- func3
- func4
+ ${strings.leafFunctions}:
+ ${strings.include}:
+ - func1
${strings.preamble}: |
// ignore_for_file: camel_case_types