Skip to content

Commit

Permalink
Pulling universal_ffi into a separate repo. Fixing License
Browse files Browse the repository at this point in the history
  • Loading branch information
vm75 committed Dec 15, 2024
1 parent 6c321fc commit 8f29dd4
Show file tree
Hide file tree
Showing 259 changed files with 1,595 additions and 6,363 deletions.
21 changes: 14 additions & 7 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
example/linux/flutter/generated_plugin_registrant.cc eol=lf
example/linux/flutter/generated_plugin_registrant.h eol=lf
example/linux/flutter/generated_plugins.cmake eol=lf
example/macos/Flutter/GeneratedPluginRegistrant.swift eol=lf
example/windows/flutter/generated_plugin_registrant.cc eol=lf
example/windows/flutter/generated_plugin_registrant.h eol=lf
example/windows/flutter/generated_plugins.cmake eol=lf
# Set the default behavior, in case people don't have core.autocrlf set.
* text eol=lf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.pdf binary
*.ico binary
*.wasm binary
*.dll binary
*.so binary
*.dylib binary
*.jar binary
*.zip binary
6 changes: 1 addition & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ on:
branches:
- main
paths:
- 'wasm_ffi/CHANGELOG.md'
- 'universal_ffi/CHANGELOG.md'
- 'CHANGELOG.md'

jobs:
analyze-and-publish:
Expand All @@ -17,7 +16,6 @@ jobs:
matrix:
package:
- wasm_ffi
- universal_ffi

steps:
- name: Checkout code
Expand All @@ -38,7 +36,6 @@ jobs:
- name: Analyze ${{ matrix.package }}
if: env.skip != 'true'
run: |
cd ${{ matrix.package }}
dart pub get
dart analyze
dart test
Expand All @@ -48,7 +45,6 @@ jobs:
env:
PUB_TOKEN: ${{ secrets.PUB_TOKEN }}
run: |
cd ${{ matrix.package }}
# Validate the package
dart pub publish --dry-run
Expand Down
9 changes: 2 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@

# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock
./pubspec.lock

# other build files
**/build/
*.a
*.out
**/.cxx/

doc/

pubspec_overrides.yaml
*.out
29 changes: 4 additions & 25 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,18 @@
"version": "0.2.0",
"configurations": [
{
"name": "wasm_ffi: example",
"name": "example",
"type": "dart",
"request": "launch",
"program": "web",
"cwd": "wasm_ffi/example",
"cwd": "example",
},
{
"name": "wasm_ffi: flutter example",
"name": "flutter example",
"type": "dart",
"request": "launch",
"program": "lib/main.dart",
"cwd": "wasm_ffi/example_flutter",
},
{
"name": "universal_ffi: web example",
"type": "dart",
"request": "launch",
"program": "web",
"cwd": "universal_ffi/example",
},
{
"name": "universal_ffi: ffi example",
"type": "dart",
"request": "launch",
"program": "bin/example.dart",
"cwd": "universal_ffi/example",
},
{
"name": "universal_ffi: ffi-plugin example",
"type": "dart",
"request": "launch",
"program": "lib/main.dart",
"cwd": "universal_ffi/example_ffi_plugin/example",
"cwd": "example_flutter",
},
]
}
3 changes: 3 additions & 0 deletions wasm_ffi/CHANGELOG.md → CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## [2.0.6]
* Pulling universal_ffi into a separate repo. Fixing License

## [2.0.5]
* Adding topics for pub.dev

Expand Down
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Copyright 2024 Vijay Mohan
Copyright 2021 Eric Prokop und Nils Wieler Hard- und Softwareentwicklung GbR
Additional Contributions Copyright 2024 vm75

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Expand Down
28 changes: 9 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
.PHONY: update-version build run
.PHONY: version build run test

update-version:
version:
bash ./tools/update-version.sh

test:
cd wasm_ffi && make test

build:
cp -f wasm_ffi/example/src/* wasm_ffi/example_flutter/src/
cp -f wasm_ffi/example/src/* universal_ffi/example/src/
cp -f wasm_ffi/example/src/* universal_ffi/example_ffi_plugin/src/
cd wasm_ffi/example && make build
cp -rf wasm_ffi/example/web/assets/* wasm_ffi/example_flutter/assets/
cp -rf wasm_ffi/example/web/assets/emscripten/* universal_ffi/example/web/assets/
cp -rf wasm_ffi/example/web/assets/emscripten/* universal_ffi/example_ffi_plugin/assets/
cp -f example/src/* example_flutter/src/
cd example && make build
cp -rf example/web/assets/* example_flutter/assets/

run-wasm:
cd wasm_ffi/example && make run
run:
cd example && make run

run-uni-web:
cd universal_ffi/example && make run-wasm

run-uni-ffi:
cd universal_ffi/example && make run-ffi
test:
dart run build_runner test -- -p chrome
130 changes: 93 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,116 @@
<div align="center">
<h1>Dart plugins for native code</h1>
</div>
<div align="center">

[![license_badge]][license_url]
[![build_badge]][build_url]

</div>

This repo contains Dart plugins to easily incorporate native(C/C++) code into Dart/Flutter projects.

# wasm_ffi

[![build_badge]][build_url]
[![github_badge]][wasm_ffi_github_url]
[![wasm_ffi_pub_ver]][wasm_ffi_pub_url]
[![wasm_ffi_pub_points]][wasm_ffi_pub_score_url]
[![wasm_ffi_pub_popularity]][wasm_ffi_pub_score_url]
[![wasm_ffi_pub_likes]][wasm_ffi_pub_score_url]
[![license_badge]][license_url]

[wasm_ffi][wasm_ffi_github_url] is a `dart:ffi` replacement for the web platform. `dart:ffi` is presently not available for the web. `wasm_ffi` enables using the same native(C/C++) code across all platforms.

# universal_ffi

[![github_badge]](https://github.com/vm75/native.ffi/tree/main/universal_ffi)
[![universal_ffi_pub_ver]][universal_ffi_pub_url]
[![universal_ffi_pub_points]][universal_ffi_pub_score_url]
[![universal_ffi_pub_popularity]][universal_ffi_pub_score_url]
[![universal_ffi_pub_likes]][universal_ffi_pub_score_url]

[universal_ffi](https://github.com/vm75/native.ffi/tree/main/universal_ffi) is a wrapper on top of `wasm_ffi` and `dart:ffi` to provide unified way to use ffi-like bindings for all platforms using the same native code.
It also has some helper methods to make it easier to use.
`wasm_ffi` intends to be a drop-in replacement for `dart:ffi` on the web platform using wasm. wasm_ffi is built on top of [web_ffi](https://pub.dev/packages/web_ffi).
The general idea is to expose an API that is compatible with `dart:ffi` but translates all calls through `dart:js` to a browser running `WebAssembly`.
Wasm with js helper as well as standalone wasm is supported. For testing emcc is used.

To simplify the usage, [universal_ffi](https://pub.dev/packages/universal_ffi) is provided, which uses `wasm_ffi` on web and `dart:ffi` on other platforms.

## Differences to dart:ffi
While `wasm_ffi` tries to mimic the `dart:ffi` API as close as possible, there are some differences. The list below documents the most importent ones, make sure to read it. For more insight, take a look at the API documentation.

* The [`DynamicLibrary`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary-class.html) `open` method is asynchronous. It also accepts some additional optional parameters.
* If more than one library is loaded, the memory will continue to refer to the first library. **This breaks calls to later loaded libraries!** One workaround is to specify the correct library.allocator for each usage of `using`.
* Each library has its own memory, so objects cannot be shared between libraries.
* Some advanced types are still unsupported.
* There are some classes and functions that are present in `wasm_ffi` but not in `dart:ffi`; such things are annotated with [`@extra`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_meta/extra-constant.html).
* There is a new class [`Memory`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/Memory-class.html) which is **IMPORTANT** and explained in deepth below.
* If you extend the [`Opaque`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Opaque-class.html) class, you must register the extended class using [`@extra registerOpaqueType<T>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/registerOpaqueType.html) before using it! Also, your class MUST NOT have type arguments (what should not be a problem).
* There are some rules concerning interacting with native functions, as listed below.

### Rules for functions
There are some rules and things to notice when working with functions:
* When looking up a function using [`DynamicLibrary.lookup<NativeFunction<NF>>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary/lookup.html) (or [`DynamicLibraryExtension.lookupFunction<T extends Function, F extends Function>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibraryExtension/lookupFunction.html)) the actuall type argument `NF` (or `T` respectively) of is not used: There is no type checking, if the function exported from `WebAssembly` has the same signature or amount of parameters, only the name is looked up.
* There are special constraints on the return type (not on parameter types) of functions `DF` (or `F` ) if you call [`NativeFunctionPointer.asFunction<DF>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/NativeFunctionPointer/asFunction.html) (or [`DynamicLibraryExtension.lookupFunction<T extends Function, F extends Function>()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibraryExtension/lookupFunction.html) what uses the former internally):
* You may nest the pointer type up to two times but not more:
* e.g. `Pointer<Int32>` and `Pointer<Pointer<Int32>>` are allowed but `Pointer<Pointer<Pointer<Int32>>>` is not.
* If the return type is `Pointer<NativeFunction>` you MUST use `Pointer<NativeFunction<dynamic>>`, everything else will fail. You can restore the type arguments afterwards yourself using casting. On the other hand, as stated above, type arguments for `NativeFunction`s are just ignored anyway.
* To concretize the things above, [return_types.md](https://github.com/vm75/wasm_ffi/blob/main/wasm_ffi/return_types.md) lists what may be used as return type, everyhing else will cause a runtime error.
* WORKAROUND: If you need something else (e.g. `Pointer<Pointer<Pointer<Double>>>`), use `Pointer<IntPtr>` and cast it yourselfe afterwards using [`Pointer.cast()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Pointer/cast.html).

### Memory
NOTE: While most of this section is still correct, some of it is now automated.
The first call you sould do when you want to use `wasm_ffi` is [`Memory.init()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/Memory/init.html). It has an optional parameter where you can adjust your pointer size. The argument defaults to 4 to represent 32bit pointers, if you use wasm64, call `Memory.init(8)`.
Contraty to `dart:ffi` where the dart process shares all the memory, on `WebAssembly`, each instance is bound to a `WebAssembly.Memory` object. For now, we assume that every `WebAssembly` module you use has it's own memory. If you think we should change that, open a issue on [GitHub](https://github.com/vm75/wasm_ffi/) and report your usecase.
Every pointer you use is bound to a memory object. This memory object is accessible using the [`@extra Pointer.boundMemory`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Pointer/boundMemory.html) field. If you want to create a Pointer using the [`Pointer.fromAddress()`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Pointer/Pointer.fromAddress.html) constructor, you may notice the optional `bindTo` parameter. Since each pointer must be bound to a memory object, you can explicitly speficy a memory object here. To match the `dart:ffi` API, the `bindTo` parameter is optional. Because it is optional, there has to be a fallback mechanism if no `bindTo` is specified: The static [`Memory.global`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi_modules/Memory/global.html) field. If that field is also not set, an exception is thrown when invoking the `Pointer.fromAddress()` constructor.
Also, each [`DynamicLibrary`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary-class.html) is bound to a memory object, which is again accessible with [`@extra DynamicLibrary.boundMemory`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/DynamicLibrary/boundMemory.html). This might come in handy, since `Memory` implements the [`Allocator`](https://pub.dev/documentation/wasm_ffi/latest/wasm_ffi/Allocator-class.html) class.


## Usage

### Install
```
dart pub add wasm_ffi
```

or
```
flutter pub add wasm_ffi
```

### Usage without ffi bindings
```dart
import 'package:wasm_ffi/ffi.dart' as ffi;
Future<void> main() async {
final library = await DynamicLibrary.open('path to wasm or js'); // NOTE: It is async
final func = library.lookupFunction<int Function(), int Function()>('functionName');
print(func());
}
```

### Usage with ffi bindings
Generates ffi bindings using [`package:ffigen`](https://pub.dev/packages/ffigen) on the header file.
In the generated bindings file, replace `import 'dart:ffi' as ffi;` with `import 'package:wasm_ffi/ffi.dart' as ffi;`

```
import 'package:wasm_ffi/ffi.dart';
import 'package:wasm_ffi/ffi_utils.dart';
import 'native_example_bindings.dart';
...
final library = await DynamicLibrary.open(libName);
final bindings = NativeExampleBindings(library);
// assuming that native library is has a function `hello` which takes a name and returns a string `Hello name!`
using((Arena arena) {
final cString = name.toNativeUtf8(allocator: arena).cast<Char>();
return bindings.hello(cString).cast<Utf8>().toDartString();
}, library.allocator); // library.allocator is optional if only one module is loaded
...
```

### build wasm

The generated wasm file needs all exported function. To ensure that, one of the two can be done:
* Use EMSCRIPTEN_KEEPALIVE annotation on all exported functions
* Define EXPORTED_FUNCTIONS when compiling the wasm

---

Contributions are welcome! 🚀

[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg
[license_url]: https://github.com/vm75/native.ffi/blob/main/LICENSE
[license_badge]: https://img.shields.io/badge/license-BSD-blue.svg
[license_url]: https://github.com/vm75/wasm_ffi/blob/main/LICENSE

[build_badge]: https://img.shields.io/github/actions/workflow/status/vm75/native.ffi/.github/workflows/publish.yml?branch=main
[build_url]: https://github.com/vm75/native.ffi/actions
[build_badge]: https://img.shields.io/github/actions/workflow/status/vm75/wasm_ffi/.github/workflows/publish.yml?branch=main
[build_url]: https://github.com/vm75/wasm_ffi/actions

[github_badge]: https://img.shields.io/badge/github-gray?style=flat&logo=Github

[wasm_ffi_pub_ver]: https://img.shields.io/pub/v/wasm_ffi
[wasm_ffi_pub_points]: https://img.shields.io/pub/points/wasm_ffi
[wasm_ffi_pub_popularity]: https://img.shields.io/pub/popularity/wasm_ffi
[wasm_ffi_pub_likes]: https://img.shields.io/pub/likes/wasm_ffi
[wasm_ffi_github_url]: https://github.com/vm75/native.ffi/tree/main/wasm_ffi
[wasm_ffi_github_url]: https://github.com/vm75/wasm_ffi
[wasm_ffi_pub_url]: https://pub.dev/packages/wasm_ffi
[wasm_ffi_pub_score_url]: https://pub.dev/packages/wasm_ffi/score

[universal_ffi_pub_ver]: https://img.shields.io/pub/v/universal_ffi
[universal_ffi_pub_points]: https://img.shields.io/pub/points/universal_ffi
[universal_ffi_pub_popularity]: https://img.shields.io/pub/popularity/universal_ffi
[universal_ffi_pub_likes]: https://img.shields.io/pub/likes/universal_ffi
[universal_ffi_github_url]: https://github.com/vm75/native.ffi/tree/main/universal_ffi
[universal_ffi_pub_url]: https://pub.dev/packages/universal_ffi
[universal_ffi_pub_score_url]: https://pub.dev/packages/universal_ffi/score
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 8f29dd4

Please sign in to comment.