dart-use-ffigen
Guide agents to use `package:ffigen` to automatically generate FFI bindings instead of writing them manually. Use this skill when a task involves writing new FFI bindings, extending C/Objective-C/Swift integrations, or replacing hand-crafted `dart:ffi` setups.
What this skill does
# Generating FFI Bindings using package:ffigen
## Contents
- [Introduction](#introduction)
- [Constraints](#constraints)
- [FFIgen Overview](#ffigen-overview)
- [Step-by-Step Workflow](#step-by-step-workflow)
- [Concrete Example: Binding a C Library](#concrete-example-binding-a-c-library)
- [Verification Checklist](#verification-checklist)
## Introduction
Automate and standardize the generation of FFI bindings using `package:ffigen` (`FfiGenerator`). Writing FFI bindings by hand is error-prone, brittle, and highly discouraged.
## Constraints
* **No Hand-Written FFI Bindings**: If native headers (`.h` files) exist or are generated by a build step, never write manual `DynamicLibrary.lookup`, `@Native` external functions, or raw struct classes. Always use `FfiGenerator` to generate them.
* **Generator Location**: The generator script should be located at `tool/ffigen.dart` within the target package root.
* **Header Location**: If the native header files are third-party, they should be located in `third_party/` within the target package (otherwise placing them in a `src/` directory at the package root is also acceptable). If the headers are not in one of these standard locations, notify the user that it would be cleaner to move the header files to the standard location (e.g., `third_party/`).
* **Targeted Inclusion Filters**: Avoid importing an entire native library unless specifically needed. Always apply precise inclusion lists using positive matches to minimize the size and cognitive load of the generated code (e.g., using `Functions.includeSet` or filtering matches in `include` closures).
* **Output Setup**: If the generated FFI bindings interface with a third-party library (or reference third-party headers), the generated files must always be placed under `lib/src/third_party/`. The primary generated FFI bindings file must strictly use the `.g.dart` extension (e.g. `sqlite3.g.dart`).
* **Preamble & License Headers**: Always supply a premium `preamble` in the `Output` class to specify the license. This must match the native third-party library's license, explicitly include the copyright header of the target native header file, and contain an automatic generation warning (e.g. `// Generated by package:ffigen. Do not edit manually.`).
* **No Unnecessary Commits of Stale Bindings**: Ensure you run the generator script and check if the generated files have changed *before* finishing your task. Always verify the package by running `dart analyze`.
* **Record Usage and Tree Shaking**: If the package is integrated into standard runtime execution or compiles native assets via native hooks:
* Enable recorded usage on all functions by setting `recordUse: (_) => true` under `Functions`.
* Specify the `recordUseMapping` target in `Output` (which must strictly be a `.g.dart` file under `lib/src/third_party/`, e.g. `lib/src/third_party/sqlite3.record_use_mapping.g.dart`) to register bindings for symbol tree shaking.
## FFIgen Overview
To construct the programmatic generator, use the core configuration objects imported from `package:ffigen/ffigen.dart`:
### 1. `FfiGenerator`
The parent class that orchestrates the configuration, parsing, and code generation.
```dart
FfiGenerator({
Headers headers = const Headers(),
Enums enums = Enums.excludeAll,
Functions functions = Functions.excludeAll,
Globals globals = Globals.excludeAll,
Integers integers = const Integers(),
Macros macros = Macros.excludeAll,
Structs structs = Structs.excludeAll,
Typedefs typedefs = Typedefs.excludeAll,
Unions unions = Unions.excludeAll,
UnnamedEnums unnamedEnums = UnnamedEnums.excludeAll,
ObjectiveC? objectiveC,
required Output output,
}).generate();
```
### 2. `Headers`
Configures Clang header parsing targets and compiler flags.
* `entryPoints`: A list of target header `Uri` inputs.
* `include`: A filter function `bool Function(Uri header)` that handles transitive header imports.
* `compilerOptions`: Custom preprocessor/include compiler flags to pass directly to libclang.
* `ignoreSourceErrors`: Set to `true` to silence errors occurring inside third-party headers during parsing.
### 3. `Functions`
Specifies which native C/C++ functions to expose in Dart.
* `include`: A matcher function (e.g. `(decl) => {'my_func'}.contains(decl.originalName)` or `Functions.includeSet({'my_func'})`).
* `isLeaf`: Declares functions as leaf functions (`(decl) => true`) if they do not call back into Dart or block thread execution.
* `recordUse`: Enables metadata generation for native asset tree shaking (essential in `dart-lang/native`). Set to `(_) => true`.
### 4. `Output`
Configures target generated files.
* `dartFile`: Target `Uri` where the primary FFI bindings will be written.
* `recordUseMapping`: Target `Uri` for recorded usage metadata maps (crucial for linking-time tree shaking).
* `preamble`: Text inserted at the top of the generated file (licensing, annotations).
* `format`: Set to `true` to run the Dart formatter automatically.
## Step-by-Step Workflow
### Step 1: Check/Add Dependencies
Open the package's `pubspec.yaml` and verify the `dev_dependencies` contains `ffigen`. Use the Dart MCP server or look up the latest version on [pub.dev](https://pub.dev/packages/ffigen) (e.g., `^20.1.1`).
You can add it automatically using the CLI:
```bash
dart pub add dev:ffigen
```
### Step 2: Formulate Paths Dynamically
Create a programmatic generator script under the package's `tool/` directory (e.g., `tool/ffigen.dart`).
Resolve paths relative to `Platform.script` to make sure it runs successfully from any working directory:
```dart
final packageRoot = Platform.script.resolve('../');
final headerFile = packageRoot.resolve('third_party/library.h');
final targetBindings = packageRoot.resolve('lib/src/third_party/bindings.g.dart');
```
### Step 3: Write the Script (`tool/ffigen.dart`)
Define `void main()` and run `FfiGenerator` with dynamic options (see complete example below).
### Step 4: Run Code Generation
Execute the script from the terminal inside the target package folder:
```bash
dart run tool/ffigen.dart
```
### Step 5: Static Analysis
Verify that the generated bindings are correct and resolve any analysis issues. FFIgen automatically runs the Dart formatter on the output file (via `format: true` configuration), so manual formatting is not required.
1. Run the static analyzer inside the target package:
```bash
dart analyze
```
2. **Addressing Warnings/Lints**: If `dart analyze` reports style or lint warnings inside the generated file, append the corresponding warning codes to the `ignore_for_file:` list in your generator script's `preamble` configuration (e.g., adding `camel_case_types`, `non_constant_identifier_names`, etc.). Do not modify the package's global rules.
3. **Addressing Compilation Errors**: If `dart analyze` reports actual compiler or analysis errors (not warnings) inside the generated file, do not attempt to edit the generated file manually. Report these error details directly to the user so they can file an issue on the repository at [github.com/dart-lang/native](https://github.com/dart-lang/native).
## Concrete Example: Binding a C Library
Let's assume we are working with the SQLite package under `pkgs/code_assets/example/sqlite`, which embeds SQLite C library sources inside `third_party/sqlite/` and accesses it via FFI.
### The C Header File (`third_party/sqlite/sqlite3.h`)
```c
// The author disclaims copyright to this source code. In place of
// a legal notice, here is a blessing:
//
// May you do good and not evil.
// May you find forgiveness for yourself and forgive others.
// May you share freely, never taking more than you give.
#ifndef SQLITE3_H_
#define SQLITE3_H_
const char *sqlite3_libversion(void);
#endif // SQLITE3_H_
```
### BEFORE: Manual FFI Binding (The Anti-Pattern)
A developer might attempt to handcraft this integration. It is fragile, blocks trRelated in Productivity
gitea-workflow
IncludedOrchestrate agile development workflows for Gitea repositories using the tea CLI. Use when working with Gitea-hosted repos and asking to 'run the workflow', 'continue working', 'what's next', 'complete the task cycle', 'start my day', 'end the sprint', 'implement the next task', or wanting guided step-by-step development assistance. Keywords: workflow, orchestrate, agile, task cycle, sprint, daily, implement, review, PR, standup, retrospective, gitea, tea.
microsoft-graph-gateway
IncludedRoute Microsoft Graph work in this workspace. Use when users want to read or write Outlook mail, calendar events, contacts, OneDrive or SharePoint files, Teams, Planner, To Do, users, groups, directory data, or arbitrary Microsoft Graph endpoints from VS Code. Prefer WorkIQ for common read scenarios. Use Microsoft Graph for write actions and gap-read scenarios that need exact Graph properties, filters, permissions, or endpoints.
copilotkit
IncludedUse when building with CopilotKit — setup, development, integrations, debugging, upgrading, or contributing. Routes to the appropriate specialized skill based on the task.
wordly-wisdom
IncludedProvides calibrated decision analysis using Charlie Munger-style multiple mental models, inversion, incentive mapping, circle-of-competence checks, misjudgment audits, second-order effects, and forecast updates. Use when the user asks for an oracle take, a hard call, a decision memo, a premortem, an outside view, a red-team, a sanity-check, what am I missing, think this through, or wants a strategy, hire, investment, plan, product, partnership, or major life choice analysed. Avoid for simple factual lookups or time-sensitive legal, medical, or market questions without fresh evidence.
swain-session
IncludedSession management and project status dashboard. Owns the full session lifecycle (start/work/close/resume), focus lane, bookmarks, worktree detection, and tab naming. Also serves as the project status dashboard — shows active epics, progress, actionable next steps, blocked items, tasks, GitHub issues, and recommendations. Worktree creation is deferred to swain-do task dispatch (SPEC-195). Triggers on: 'session', 'status', 'what's next', 'dashboard', 'overview', 'where are we', 'what should I work on', 'show me priorities', 'bookmark', 'focus on', 'session info'.
gandi
IncludedComprehensive Gandi domain registrar integration for domain and DNS management. Register and manage domains, create/update/delete DNS records (A, AAAA, CNAME, MX, TXT, SRV, and more), configure email forwarding and aliases, check SSL certificate status, create DNS snapshots for safe rollback, bulk update zone files, and monitor domain expiration. Supports multi-domain management, zone file import/export, and automated DNS backups. Includes both read-only and destructive operations with safety controls.