Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
90cee4c
wip
liamappelbe Aug 10, 2026
5b86450
Lazy AST node wrappers
liamappelbe Aug 10, 2026
6e419f8
Don't visit children of excluded elements
liamappelbe Aug 10, 2026
b9226e4
wip
liamappelbe Aug 10, 2026
bddcbee
wip
liamappelbe Aug 11, 2026
a2996b4
wip
liamappelbe Aug 11, 2026
8ae873a
fixes
liamappelbe Aug 11, 2026
afd1c2f
bindings
liamappelbe Aug 11, 2026
96a42e0
Merge branch 'main' into ffigen_config_update_4
liamappelbe Aug 11, 2026
8e7fff0
clean up
liamappelbe Aug 11, 2026
a68e55f
clean up
liamappelbe Aug 11, 2026
21c4256
clean up
liamappelbe Aug 12, 2026
886635f
wip
liamappelbe Aug 12, 2026
ed80eb2
manual clean up
liamappelbe Aug 12, 2026
370fb10
regen
liamappelbe Aug 12, 2026
0a19f86
regen
liamappelbe Aug 12, 2026
79643a1
wip
liamappelbe Aug 12, 2026
80e8e1d
restore comment
liamappelbe Aug 12, 2026
7de78e5
revert unnecessary diff
liamappelbe Aug 12, 2026
592673f
revert spurious diff
liamappelbe Aug 12, 2026
243c02b
revert scope
liamappelbe Aug 12, 2026
5c368de
fix tests
liamappelbe Aug 12, 2026
f449200
clean
liamappelbe Aug 12, 2026
5541c18
docs
liamappelbe Aug 12, 2026
7bdf73b
revert junk
liamappelbe Aug 12, 2026
20d6fe8
clean up
liamappelbe Aug 12, 2026
0f0816c
regen
liamappelbe Aug 12, 2026
073fd94
fix
liamappelbe Aug 12, 2026
7076663
clean up
liamappelbe Aug 12, 2026
369f3d3
fix diffs
liamappelbe Aug 12, 2026
b8545e4
dediff
liamappelbe Aug 13, 2026
ed67128
fmt
liamappelbe Aug 13, 2026
bb3f278
fmt
liamappelbe Aug 13, 2026
f2e02e0
Merge branch 'main' into ffigen_config_update_4
liamappelbe Aug 13, 2026
a4bb0b7
wip
liamappelbe Aug 13, 2026
2af5f68
fix
liamappelbe Aug 13, 2026
02e8c3f
fix some tests
liamappelbe Aug 13, 2026
dab4b83
Fix tests
liamappelbe Aug 13, 2026
0bcbfdd
clean up
liamappelbe Aug 13, 2026
eb76e77
clean up
liamappelbe Aug 13, 2026
bb5543d
fix category bug
liamappelbe Aug 13, 2026
195d2b5
fix
liamappelbe Aug 13, 2026
090ddb6
cleaning
liamappelbe Aug 14, 2026
8fa206f
clean up example
liamappelbe Aug 14, 2026
f74dd48
clean up
liamappelbe Aug 14, 2026
01f2959
clean up
liamappelbe Aug 14, 2026
c68cee0
Merge branch 'main' into ffigen_config_update_4
liamappelbe Aug 14, 2026
f224827
migrate monorepo configs
liamappelbe Aug 14, 2026
05bb981
clean up
liamappelbe Aug 14, 2026
dae5b31
changelog
liamappelbe Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions pkgs/code_assets/example/host_name/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import 'package:ffigen/ffigen.dart';

void main() {
final packageRoot = Platform.script.resolve('../');
final functions = Functions.includeSet({'gethostname'});
final visitors = [
Visitor(visitFunc: (node) => node.isIncluded = node.name == 'gethostname'),
];
final FfiGenerator generator;
if (Platform.isWindows) {
generator = FfiGenerator(
input: Input(entryPoints: [packageRoot.resolve('src/windows.h')]),
functions: functions,
visitors: visitors,
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/windows.dart'),
preamble: '''
Expand All @@ -27,7 +29,7 @@ void main() {
} else {
generator = FfiGenerator(
input: Input(entryPoints: [packageRoot.resolve('src/unix.h')]),
functions: functions,
visitors: visitors,
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/unix.dart'),
preamble: '''
Expand Down
28 changes: 13 additions & 15 deletions pkgs/code_assets/example/mini_audio/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ void main() {
final packageRoot = Platform.script.resolve('../');
FfiGenerator(
input: Input(entryPoints: [packageRoot.resolve('third_party/miniaudio.h')]),
functions: Functions(
include: (decl) => {
'ma_engine_init',
'ma_engine_play_sound',
'ma_engine_uninit',
}.contains(decl.originalName),
recordUse: (_) => true,
),
structs: Structs(
include: (decl) => {'ma_engine'}.contains(decl.originalName),
),
enums: Enums(
include: (decl) => {'ma_result'}.contains(decl.originalName),
silenceWarning: true,
),
functions: Functions(recordUse: (_) => true),
enums: const Enums(silenceWarning: true),
visitors: [
Visitor(
visitFunc: (node) => node.isIncluded = {
'ma_engine_init',
'ma_engine_play_sound',
'ma_engine_uninit',
}.contains(node.name),
visitStruct: (node) => node.isIncluded = node.name == 'ma_engine',
visitEnum: (node) => node.isIncluded = node.name == 'ma_result',
),
],
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/miniaudio.g.dart'),
recordUseMapping: packageRoot.resolve(
Expand Down
11 changes: 7 additions & 4 deletions pkgs/code_assets/example/sqlite/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ void main() {
input: Input(
entryPoints: [packageRoot.resolve('third_party/sqlite/sqlite3.h')],
),
functions: Functions(
include: (decl) => {'sqlite3_libversion'}.contains(decl.originalName),
recordUse: (_) => true,
),
functions: Functions(recordUse: (_) => true),
visitors: [
Visitor(
visitFunc: (node) =>
node.isIncluded = node.name == 'sqlite3_libversion',
),
],
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/sqlite3.g.dart'),
recordUseMapping: packageRoot.resolve(
Expand Down
7 changes: 6 additions & 1 deletion pkgs/code_assets/example/sqlite_no_link/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ void main() {
input: Input(
entryPoints: [packageRoot.resolve('third_party/sqlite/sqlite3.h')],
),
functions: Functions.includeSet({'sqlite3_libversion'}),
visitors: [
Visitor(
visitFunc: (node) =>
node.isIncluded = node.name == 'sqlite3_libversion',
),
],
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/sqlite3.g.dart'),
preamble: '''
Expand Down
7 changes: 6 additions & 1 deletion pkgs/code_assets/example/sqlite_prebuilt/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ void main() {
input: Input(
entryPoints: [packageRoot.resolve('third_party/sqlite/sqlite3.h')],
),
functions: Functions.includeSet({'sqlite3_libversion'}),
visitors: [
Visitor(
visitFunc: (node) =>
node.isIncluded = node.name == 'sqlite3_libversion',
),
],
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/sqlite3.g.dart'),
preamble: '''
Expand Down
8 changes: 4 additions & 4 deletions pkgs/code_assets/example/stb_image/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ void main() {
final packageRoot = Platform.script.resolve('../');
FfiGenerator(
input: Input(entryPoints: [packageRoot.resolve('third_party/stb_image.h')]),
functions: Functions(
include: (decl) => {'stbi_info'}.contains(decl.originalName),
recordUse: (_) => true,
),
functions: Functions(recordUse: (_) => true),
visitors: [
Visitor(visitFunc: (node) => node.isIncluded = node.name == 'stbi_info'),
],
output: Output(
dartFile: packageRoot.resolve('lib/src/third_party/stb_image.g.dart'),
recordUseMapping: packageRoot.resolve(
Expand Down
1 change: 1 addition & 0 deletions pkgs/ffigen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- __Breaking change__: Major overhaul of Dart config API:
- Replace various callback based config elements with a `Visitor` pattern.
- `rename` and `renameMember` replaced with `.name` setters on AST nodes.
- `include` and `includeMember` replaced with `.isIncluded` on AST nodes.
- Consolidate `imported` fields and `importedTypesByUsr` into
`FfiGenerator.importType`, switching it to a callback pattern
- Deleted empty `Integers` class
Expand Down
8 changes: 5 additions & 3 deletions pkgs/ffigen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,18 @@ app has been created via `dart create ffigen_example`.
import 'dart:io';

import 'package:ffigen/ffigen.dart';

void main() {
final packageRoot = Platform.script.resolve('../');
FfiGenerator(
// Required. Output path for the generated bindings.
output: Output(dartFile: packageRoot.resolve('lib/add.g.dart')),
// Optional. Where to look for header files.
input: Input(entryPoints: [packageRoot.resolve('src/add.h')]),
// Optional. What functions to generate bindings for.
functions: Functions.includeSet({'add'}),
// Optional. Transform and filter AST nodes.
visitors: [
Visitor(visitFunc: (node) => node.isIncluded = node.name == 'add'),
],
).generate();
}
```
Expand Down
4 changes: 3 additions & 1 deletion pkgs/ffigen/example/add/tool/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ FfiGenerator getConfig(Uri packageRoot) {
return FfiGenerator(
output: Output(dartFile: packageRoot.resolve('lib/add.g.dart')),
input: Input(entryPoints: [packageRoot.resolve('src/add.h')]),
functions: Functions.includeSet({'add'}),
visitors: [
Visitor(visitFunc: (node) => node.isIncluded = node.name == 'add'),
],
);
}

Expand Down
10 changes: 5 additions & 5 deletions pkgs/ffigen/example/objective_c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ dart play_audio.dart test.mp3

The FFIgen config for an Objective C library looks very similar to a C library.
The most important difference is that you must set `FfiGenerator.objectiveC`.
If you want to filter which interfaces are included you can use the
`FfiGenerator.objectiveC.interfaces` option.
This works similarly to the other filtering options.
If you want to filter which interfaces are included, you can use the
`FfiGenerator.visitors` option to inspect AST nodes and set `node.isIncluded = true`
on the interfaces you want to generate.

It is recommended that you filter out just about everything you're not
interested in binding (see the FFIgen config in [pubspec.yaml](./pubspec.yaml)).
interested in binding (see the FFIgen config in [generate_code.dart](./generate_code.dart)).
Virtually all Objective C libraries depend on Apple's internal libraries, which
are huge. Filtering can reduce the generated bindings from millions of lines to
thousands.
Expand All @@ -25,7 +25,7 @@ In this example, we're only interested in `AVAudioPlayer`, so we've filtered out
everything else. FFIgen will automatically pull in anything referenced by
any of the fields or methods of `AVAudioPlayer`, but by default they're
generated as stubs. To generate full bindings for the transient dependencies,
add them to your include set, or set `Interfaces.includeTransitive` to `true`.
set `node.isIncluded = true` for them in your visitor, or set `Interfaces.includeTransitive` to `true`.

## Generating bindings

Expand Down
20 changes: 15 additions & 5 deletions pkgs/ffigen/example/objective_c/generate_code.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,21 @@ final config = FfiGenerator(

// To tell FFIgen to generate Objective-C bindings, rather than C bindings,
// set the objectiveC field to a non-null value.
objectiveC: ObjectiveC(
// The interfaces field is used to tell FFIgen which interfaces to generate
// bindings for. There's also a protocols and a categories field.
interfaces: Interfaces.includeSet({'AVAudioPlayer'}),
),
objectiveC: const ObjectiveC(),
visitors: [
Visitor(
// The visitObjCInterface function is invoked for each interface
// discovered while parsing the entryPoints.
visitObjCInterface: (node) {
if (node.name == 'AVAudioPlayer') {
// API elements like interfaces are excluded from the generated
// bindings by default. So choose the ones you want to include and set
// .isIncluded to true.
node.isIncluded = true;
}
},
),
],

output: Output(
// The Dart file where the bindings will be generated.
Expand Down
3 changes: 1 addition & 2 deletions pkgs/ffigen/lib/ffigen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export 'src/config_provider.dart'
CommentStyle,
CommentType,
CompoundDependencies,
Cpp,
Declaration,
Declarations,
DynamicLibraryBindings,
Expand All @@ -33,7 +34,6 @@ export 'src/config_provider.dart'
Globals,
Input,
Interfaces,
Macros,
NativeExternalBindings,
ObjectiveC,
Output,
Expand All @@ -43,7 +43,6 @@ export 'src/config_provider.dart'
SymbolFile,
Typedefs,
Unions,
UnnamedEnums,
VarArgFunction,
Version,
Versions,
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/compound.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ abstract class Compound extends BindingType with HasLocalScope {
/// incomplete, opaque, or has an unknown layout at parse time.
final int? sizeInBytes;

bool isIncluded = false;

Compound({
super.usr,
super.originalName,
Expand Down
5 changes: 5 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/constant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Constant extends NoLookUpBinding {

final ApiAvailability? apiAvailability;

bool isIncluded = false;

Constant({
super.usr,
super.originalName,
Expand Down Expand Up @@ -61,6 +63,9 @@ class Constant extends NoLookUpBinding {
);
}

@override
public_ast.AstNode? toPublicAstNode() => public_ast.Constant(this);

@override
void visit(Visitation visitation) => visitation.visitConstant(this);
}
Expand Down
3 changes: 3 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/cpp_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class CppMethod extends AstNode with HasLocalScope {
final bool isStatic;
final CppMethodKind kind;

bool isIncluded = true;

CppMethod({
required this.name,
required this.originalName,
Expand Down Expand Up @@ -70,6 +72,7 @@ class CppClass extends BindingType with HasLocalScope {
final Context context;
final List<CppMethod> methods;
final List<CppMember> fields;
bool isIncluded = false;

CppClass({
super.usr,
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/enum_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class EnumClass extends BindingType with HasLocalScope {

final ApiAvailability? apiAvailability;

bool isIncluded = false;

EnumClass({
super.usr,
super.originalName,
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/func.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Func extends LookUpBinding with HasLocalScope {
/// Contains typealias for function type if [exposeFunctionTypedefs] is true.
Typealias? _exposedFunctionTypealias;

bool isIncluded = false;

/// [originalName] is looked up in dynamic library, if not
/// provided, takes the value of [name].
Func({
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/global.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Global extends LookUpBinding with HasLocalScope {
@override
final bool loadFromNativeAsset;

bool isIncluded = false;

Global({
super.usr,
super.originalName,
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/objc_category.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class ObjCCategory extends NoLookUpBinding with ObjCMethods, HasLocalScope {

final ApiAvailability apiAvailability;

bool isIncluded = false;

ObjCCategory({
super.usr,
required String super.originalName,
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/objc_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class ObjCInterface extends BindingType with ObjCMethods, HasLocalScope {
// Filled by ListBindingsVisitation.
bool generateAsStub = false;

bool isIncluded = false;

ObjCInterface({
super.usr,
required String super.originalName,
Expand Down
3 changes: 3 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/objc_methods.dart
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class ObjCMethod extends AstNode with HasLocalScope {
Symbol? protocolMethodName;
ObjCMethods? parent;
ObjCMethod? setter;
bool isIncluded = true;

@override
void visitChildren(Visitor visitor, {bool omitMethodName = false}) {
Expand Down Expand Up @@ -350,6 +351,7 @@ class ObjCMethod extends AstNode with HasLocalScope {
);
clonedMethod.parent = parent;
clonedMethod.protocolMethodName = protocolMethodName?.clone();
clonedMethod.isIncluded = isIncluded;
return clonedMethod;
}

Expand All @@ -364,6 +366,7 @@ class ObjCMethod extends AstNode with HasLocalScope {
clonedSymbol,
parent: parent,
);
clonedSetter.isIncluded = clonedMethod.isIncluded;
clonedMethod.setter = clonedSetter;
}
return clonedMethod;
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/objc_protocol.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ObjCProtocol extends BindingType with ObjCMethods, HasLocalScope {
// Filled by ListBindingsVisitation.
bool generateAsStub = false;

bool isIncluded = false;

ObjCProtocol({
super.usr,
required String super.originalName,
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/typealias.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class Typealias extends BindingType {
// Don't code gen this alias at all, just use the [type] directly.
bool isAnonymous;

bool isIncluded = false;

/// Creates a Typealias.
///
/// If [genFfiDartType] is true, a binding is generated for the Ffi Dart type
Expand Down
1 change: 1 addition & 0 deletions pkgs/ffigen/lib/src/code_generator/union.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Union extends Compound {
super.isIncomplete,
super.dartDoc,
super.members,
super.isInternal,
required super.context,
super.nativeType,
super.apiAvailability,
Expand Down
Loading
Loading