Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
75 changes: 75 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
validate-and-test:
name: Validate & Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Checkout wasm_ffi
uses: actions/checkout@v4
with:
repository: vm75/wasm_ffi
path: wasm_ffi-temp

- name: Set up local wasm_ffi sibling
run: |
mkdir -p ../wasm_ffi
cp -r wasm_ffi-temp/* ../wasm_ffi/
rm -rf wasm_ffi-temp
sed -i 's/version: 2.3.0/version: 2.4.0/' ../wasm_ffi/pubspec.yaml || true

- name: Set up Dart
uses: dart-lang/setup-dart@v1
with:
sdk: stable

- name: Install dependencies
run: dart pub get

- name: Verify formatting
run: dart format --output=none --set-exit-if-changed .

- name: Analyze package
run: dart analyze lib test example

- name: Run VM tests
run: dart test

- name: Validate package dry-run
run: dart pub publish --dry-run

- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable

- name: Analyze Flutter plugin
working-directory: example_ffi_plugin
run: |
flutter pub get
flutter analyze

- name: Analyze Flutter plugin example
working-directory: example_ffi_plugin/example
run: |
flutter pub get
flutter analyze

- name: Build Flutter Web (dart2js)
working-directory: example_ffi_plugin/example
run: flutter build web

- name: Build Flutter Web (dart2wasm)
working-directory: example_ffi_plugin/example
run: flutter build web --wasm
26 changes: 13 additions & 13 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,36 @@ jobs:
analyze-and-publish:
name: Analyze and Publish Dart Packages
runs-on: ubuntu-latest

strategy:
matrix:
package:
- universal_ffi
permissions:
id-token: write
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Set up Dart
uses: dart-lang/setup-dart@v1
with:
channel: stable
sdk: stable

- name: Check if relevant CHANGELOG is updated
- name: Check if CHANGELOG is updated
id: changes
run: |
if [[ ! $(git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep "^${{ matrix.package }}/CHANGELOG.md$") ]]; then
echo "skip=true" >> $GITHUB_ENV
if ! git diff --name-only HEAD~1 HEAD | grep -q '^CHANGELOG.md$'; then
echo "skip=true" >> "$GITHUB_ENV"
fi

- name: Analyze ${{ matrix.package }}
- name: Analyze universal_ffi
if: env.skip != 'true'
run: |
dart pub get
dart analyze
dart test

- name: Publish ${{ matrix.package }} (if valid)
- name: Publish universal_ffi (if valid)
if: env.skip != 'true'
env:
PUB_TOKEN: ${{ secrets.PUB_TOKEN }}
Expand All @@ -49,5 +49,5 @@ jobs:
dart pub publish --dry-run

# Publish the package if validation succeeds
echo "Publishing ${{ matrix.package }} to pub.dev..."
echo "Publishing universal_ffi to pub.dev..."
# dart pub publish --force
52 changes: 52 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Agent Guide for universal_ffi

## Project overview
`universal_ffi` is a cross-platform Dart library providing a unified Foreign Function Interface (FFI) abstraction across native platforms (via `dart:ffi` / `package:ffi`) and the web (via `wasm_ffi`). It enables pure Dart packages and Flutter FFI plugins to write portable C/C++ interop code and load platform-specific dynamic libraries (`.so`, `.dylib`, `.dll`, `.wasm`, `.js`) with unified helpers.

## Repository map
- `lib/` — Public package entry points (`ffi.dart`, `ffi_helper.dart`, `ffi_utils.dart`).
- `lib/src/dart_ffi/` — Native platform implementations backed by `dart:ffi` and `package:ffi`.
- `lib/src/wasm_ffi/` — Web implementations backed by `wasm_ffi`.
- `test/` — Unit, integration, and path resolution test suites.
- `example/` — Pure Dart CLI and web example project demonstrating `universal_ffi` usage and bindings.
- `example_ffi_plugin/` — Flutter FFI plugin example showing multi-platform C/C++ builds with Emscripten and CMake.
- `tool/update-version.sh` — Interactive versioning, changelog update, and release preparation script.
- `.github/workflows/ci.yml` — Continuous integration testing and validation workflow.
- `.github/workflows/publish.yml` — Workflow triggered on changelog updates for analysis, testing, and dry-run publishing.

## Working commands
- Setup / Dependencies: `dart pub get`
- Static Analysis / Lint: `dart analyze`
- Tests: `dart test`
- Package Validation: `dart pub publish --dry-run`
- Version Management: `make version` (or `bash ./tool/update-version.sh`)
- Build Example Plugin Assets: `make build` (in `example_ffi_plugin/`)
- Run Web Example: `make run-web` (in `example/` via `webdev serve`)
- Run Native Example: `make run-ffi` (in `example/` via `dart run`)

## Engineering constraints
- Follow KISS and YAGNI; keep the core wrapper minimal and focused on bridging `dart:ffi` and `wasm_ffi`.
- Preserve conditional export separation (`dart.library.ffi` vs Web/WASM) across `lib/ffi.dart`, `lib/ffi_utils.dart`, and `lib/ffi_helper.dart`.
- `wasm_ffi` does not support `Array`, `Struct`, and `Union`; preserve compatibility constraints and do not introduce dependencies on unsupported constructs.
- Use `FfiHelper.safeUsing` or `FfiHelper.safeWithZoneArena` when multiple WASM modules are involved to prevent allocator collisions across module boundaries.
- Respect `LoadOption` conventions (`isStaticallyLinked`, `isFfiPlugin`, `isStandaloneWasm`) in `resolveModulePath`. Note that statically linked libraries (`DynamicLibrary.process()`) are unsupported on Web.

## Context discipline
- Start with targeted search and the repository map before opening files.
- Read only files relevant to the task and follow linked documentation as needed.
- Do not load generated files, `.dart_tool/`, `.vscode/`, or compiled native/WASM binaries unless diagnosing build or asset packaging issues.

## Documentation routing
- User setup, usage guide, and plugin development: [`README.md`](README.md)
- Release history: [`CHANGELOG.md`](CHANGELOG.md)

## Definition of done
- Static analysis passes with no issues: `dart analyze`.
- Package dry-run validation passes with zero warnings: `dart pub publish --dry-run`.
- Public APIs and conditional exports maintain parity across native and web targets.
- Only documentation made inaccurate by the change was updated.

## Documentation maintenance
- Update `AGENTS.md` only when agent workflow, verified commands, navigation, or architectural constraints change.
- Update `README.md` only when user-facing setup, API capabilities, plugin guides, or requirements change.
- Update `CHANGELOG.md` when preparing a new package release.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# CHANGELOG

## [1.5.1]

* Update minimum `wasm_ffi` dependency to `^2.4.0`.
* Inherit dart2wasm and Flutter `--wasm` support for standalone WebAssembly modules via `wasm_ffi 2.4.0`.
* Add comprehensive unit and integration test coverage across Web/Native path resolution, `FfiHelper` allocator safety, and standalone Wasm invocation.
* Harden CI workflows with PR validation, static analysis, dry-run checks, and fix publish workflow changelog path inspection.

## [1.5.0]

* Using wasm_ffi 2.3.0 with important memory fix
Expand Down
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,33 @@
[![universal_ffi_pub_likes]][universal_ffi_pub_score_url]
[![license_badge]][license_url]

`universal_ffi` is a wrapper on top of `wasm_ffi` and `dart:ffi` to provide a consistent API across all platforms.
It also has some helper methods to make it easier to use.
`universal_ffi` is a thin cross-platform facade on top of `wasm_ffi` (for Web) and `dart:ffi` (for native platforms) to provide a consistent API across all platforms.
It also includes helper utilities for platform-aware library loading and memory management.

`wasm_ffi` has a few limitations, so some of the features of `dart:ffi` are not supported. Most notably:
With `wasm_ffi 2.4.0`, `universal_ffi` supports standalone WebAssembly modules when the consuming Dart or Flutter Web application itself is compiled with `dart2wasm` / Flutter `--wasm`, in addition to standard Dart Web (dart2js) and native desktop/mobile platforms. Low-level WebAssembly marshalling and runtime mechanics are managed by `wasm_ffi`.

`wasm_ffi` has a few limitations, so some features of `dart:ffi` are not supported on Web:

* Array
* Struct
* Union

## Requirements

- Dart SDK: `^3.10.8`
- Flutter SDK (for Flutter plugins): `>=3.3.0`

## Usage

### Install

```dart
```sh
dart pub add universal_ffi
```

or

```dart
```sh
flutter pub add universal_ffi
```

Expand Down Expand Up @@ -219,6 +226,28 @@ emcc -o path/to/moduleName.wasm \
* **Emscripten JS**: Output `moduleName.js` (and `moduleName.wasm` will be generated next to it).
* **Standalone WASM**: Output `moduleName.wasm`.

## Development

```sh
# Fetch dependencies
dart pub get

# Run static analysis
dart analyze

# Validate package publishing prerequisites
dart pub publish --dry-run
```

## Documentation

- [Agent Guide](AGENTS.md)
- [Release History](CHANGELOG.md)

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

Contributions are welcome! 🚀
Expand Down
4 changes: 2 additions & 2 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ analyzer:
missing_return: error
# parameter_assignments: warning

# exclude:
# - example/
exclude:
- example_ffi_plugin/**

linter:
rules:
Expand Down
4 changes: 4 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ dev_dependencies:
build_web_compilers: ^4.0.9
lints: ^4.0.0
ffigen: ^14.0.0

dependency_overrides:
wasm_ffi:
path: ../../wasm_ffi
5 changes: 4 additions & 1 deletion example_ffi_plugin/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,17 @@ class _AsyncRunnerWidgetState extends State<AsyncRunnerWidget> {
// Simulated asynchronous runner.
Future<Map<String, String>> fetchValues() async {
await init(widget.libPath);
return {
final results = {
'Library Name': getLibraryName(),
'Hello String': hello(widget.libPath),
'Size of Int': sizeOfInt().toString(),
'Size of Bool': sizeOfBool().toString(),
'Size of Pointer': sizeOfPointer().toString(),
'Static Init Check': staticInitCheck().toString(),
};
// ignore: avoid_print
print('[RESULT] ${widget.libPath}: $results');
return results;
}

// Load data using the asynchronous runner
Expand Down
4 changes: 4 additions & 0 deletions example_ffi_plugin/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ dev_dependencies:
sdk: flutter
flutter_lints: ^5.0.0

dependency_overrides:
wasm_ffi:
path: ../../../wasm_ffi

flutter:
uses-material-design: true
4 changes: 4 additions & 0 deletions example_ffi_plugin/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ dev_dependencies:
sdk: flutter
flutter_lints: ^5.0.0

dependency_overrides:
wasm_ffi:
path: ../../wasm_ffi

flutter:
plugin:
platforms:
Expand Down
8 changes: 6 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: universal_ffi
description: A drop-in replacement for dart:ffi for all platforms including web (using wasm_ffi).
version: 1.5.0
version: 1.5.1
repository: https://github.com/vm75/universal_ffi

environment:
Expand All @@ -9,12 +9,16 @@ environment:
dependencies:
ffi: ^2.1.5
path: ^1.9.1
wasm_ffi: ^2.3.0
wasm_ffi: ^2.4.0

dev_dependencies:
lints: ^6.1.0
test: ^1.29.0

dependency_overrides:
wasm_ffi:
path: ../wasm_ffi

topics:
- ffi
- wasm
Expand Down
Loading
Loading