-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FFIgenPad #1390
base: main
Are you sure you want to change the base?
FFIgenPad #1390
Changes from all commits
67b39c8
af7d2e4
4ce5c06
e862969
9bf1b10
a40ca94
307e760
46e3e23
79cb95e
5e6c243
bd0122b
46ceb47
ed74146
4069841
fd84f55
b5adb4f
3f38614
aa15b0d
0de06c0
3940d70
22b5f83
b8111ec
463985e
1155d8e
35e5f0e
bf85ca5
3bed03c
6180832
d0bbe2b
75e6994
a93e9fa
e27bbbd
0745838
6dd84d5
7c1622f
7cfcc6e
482bcd0
b1f3c8e
17d3160
810a15d
6299659
1234beb
00bf3d5
b3683d8
08093ef
c8f4c7e
e8aabd4
767a31b
6e08436
40aa56e
16ea78d
707ddd7
1b9dd4e
5fb9226
29f2420
cbd724b
30ccf19
599c7f3
0fe1b5d
4a2770d
f76f384
e939fe9
6e825dc
ed4c0b2
28eb19e
f9bb818
c422826
dfa6ad4
32da58a
6e3ffbf
1173d97
7629f14
c62228e
ddee6ae
c1e8ee9
d7e5a84
ef7dd9e
65c4cf5
1c914f5
0a1d16c
64e3d54
9df674a
bb901de
d93dfe1
c832daf
4a50419
9100d5f
fcf5d22
4877bd9
e378701
fad58d0
7c8c7ae
b875ff2
8d2d296
c42f950
1f34b13
c9dab50
a5bb1ab
1596ae3
e43f341
e5af39a
9fec5c5
62ffe45
8e73e43
f5b4f5e
8e266bc
7c5fc5c
945e1e0
60d9799
8485fdc
9ef321d
4df8cbf
a5dac1f
6daf9a6
c3d84d5
b39a9bf
06925e6
01eacb6
4806041
19d19ff
f4b654f
1755e12
2312d63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
name: ffigenpad | ||
|
||
on: | ||
pull_request: | ||
branches: [main] | ||
paths: | ||
- ".github/workflows/ffigenpad.yaml" | ||
- "pkgs/ffigenpad/**" | ||
push: | ||
branches: [main] | ||
paths: | ||
- ".github/workflows/ffigenpad.yaml" | ||
- "pkgs/ffigenpad/**" | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 | ||
|
||
- uses: dart-lang/setup-dart@e9a814f39d5452701455a47847735e0f482026c8 | ||
with: | ||
sdk: dev | ||
|
||
- run: dart pub get | ||
working-directory: pkgs/ffigenpad | ||
|
||
- uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 | ||
with: | ||
version: 3.1.61 | ||
|
||
- name: setup ffigenpad | ||
working-directory: pkgs/ffigenpad | ||
run: dart run tool/setup.dart | ||
|
||
- name: build libclang.wasm | ||
working-directory: pkgs/ffigenpad | ||
run: dart run tool/build_libclang.dart --optimize | ||
|
||
- name: build ffigenpad | ||
working-directory: pkgs/ffigenpad | ||
run: | | ||
dart compile wasm ./lib/ffigenpad.dart -o ./bin/ffigenpad.wasm -O3 \ | ||
--extra-compiler-option=--enable-experimental-ffi \ | ||
--extra-compiler-option=--enable-experimental-wasm-interop | ||
|
||
- uses: pnpm/action-setup@ac5bf11548bf5e19b8aadb8182072616590fa4a6 | ||
with: | ||
version: 9.7.0 | ||
run_install: | | ||
- cwd: pkgs/ffigenpad/web | ||
|
||
- uses: actions/configure-pages@aabcbc432d6b06d1fd5e8bf3cf756880c35e014d | ||
|
||
- name: build website | ||
working-directory: pkgs/ffigenpad/web | ||
run: pnpm build | ||
|
||
- uses: actions/upload-pages-artifact@1780dfc2cece65a782cc86fa133f96aef8ad0345 | ||
with: | ||
path: pkgs/ffigenpad/web/dist | ||
|
||
deploy: | ||
needs: build | ||
runs-on: ubuntu-latest | ||
permissions: | ||
pages: write | ||
id-token: write | ||
environment: | ||
name: github-pages | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gives an error here according to the editor, but seems to be consistent with the documentation. |
||
url: ${{ steps.deployment.outputs.page_url }} | ||
steps: | ||
- uses: actions/deploy-pages@b74272834adc04f971da4b0b055c49fa8d7f90c9 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## 0.1.0 | ||
|
||
- Initial version. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# FFIgenPad | ||
|
||
A web interface in which you paste a C header in a textbox on the left, and it outputs `dart:ffi` bindings generated by `package:ffigen` in a textbox on the right. (Inspiration is https://godbolt.org/ which does this for a C file on the left and assembly on the right.) | ||
|
||
It doesn't need a server cause it compiles the Dart code in `package:ffigen` and libclang to WASM. That way everything can run in the browser. | ||
|
||
------ | ||
|
||
## Project Structure | ||
|
||
Most of the files in `lib/src/` are copied from the source of *ffigen* with modifications to make it compatible with dart2wasm (many of the workarounds are listed in [this blog article](https://thecomputerm.hashnode.dev/dirty-deeds-done-dart-cheap-experiments-with-dart2wasm)). | ||
|
||
However the files listed do not have an ffigen counterpart: | ||
- [./lib/ffigenpad.dart](./lib/ffigenpad.dart) | ||
- [./lib/memfs.dart](./lib/memfs.dart) | ||
- [./lib/src/header_parser/calloc.dart](./lib/src/header_parser/calloc.dart) | ||
- [./lib/src/header_parser/clang_bindings/clang_types.dart](./lib/src/header_parser/clang_bindings/clang_types.dart) | ||
- [./lib/src/header_parser/clang_bindings/clang_wrapper.dart](./lib/src/header_parser/clang_bindings/clang_wrapper.dart) | ||
|
||
## Building | ||
|
||
### Prerequisites | ||
|
||
- dart | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minimal version? (Fine to mention just today's dev release if that's good enough.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It works with dart stable v3.5.1, should I also update it in github actions? |
||
- emscripten (>= 3.1.61) | ||
- for website | ||
- nodejs (>= ^20.17.0) | ||
- pnpm (optional but recommended) | ||
|
||
### Steps | ||
|
||
- Run `tool/setup.dart` to download LLVM archive files to build *libclang.wasm* | ||
|
||
```sh | ||
# in project root | ||
dart run tool/setup.dart | ||
``` | ||
|
||
- Run `tool/build_libclang.dart` to build *libclang.wasm* using functions exported from *third_party/libclang/libclang.exports* | ||
|
||
```sh | ||
# in project root | ||
dart run tool/build_libclang.dart | ||
``` | ||
|
||
- Build FFIgenPad using the experimental dart2wasm compiler | ||
|
||
```sh | ||
# in project root | ||
dart compile wasm ./lib/ffigenpad.dart -o ./bin/ffigenpad.wasm \ | ||
--extra-compiler-option=--enable-experimental-ffi \ | ||
--extra-compiler-option=--enable-experimental-wasm-interop | ||
``` | ||
|
||
- To build the website | ||
|
||
```sh | ||
# in project root | ||
cd web | ||
npm i # install dependencies | ||
TheComputerM marked this conversation as resolved.
Show resolved
Hide resolved
|
||
npm run build | ||
TheComputerM marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# preview with: npm run preview | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. http://localhost:4173/ -> 404 |
||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# This file configures the static analysis results for your project (errors, | ||
# warnings, and lints). | ||
# | ||
# This enables the 'recommended' set of lints from `package:lints`. | ||
# This set helps identify many issues that may lead to problems when running | ||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic | ||
# style and format. | ||
# | ||
# If you want a smaller set of lints you can change this to specify | ||
# 'package:lints/core.yaml'. These are just the most critical lints | ||
# (the recommended set includes the core lints). | ||
# The core lints are also what is used by pub.dev for scoring packages. | ||
|
||
include: package:dart_flutter_team_lints/analysis_options.yaml | ||
|
||
# Uncomment the following section to specify additional rules. | ||
|
||
linter: | ||
rules: | ||
implementation_imports: false | ||
|
||
analyzer: | ||
errors: | ||
todo: ignore | ||
language: | ||
strict-casts: true | ||
strict-inference: true | ||
strict-raw-types: true | ||
# For more information about the core and recommended set of lints, see | ||
# https://dart.dev/go/core-lints | ||
|
||
# For additional information about configuring this file, see | ||
# https://dart.dev/guides/language/analysis-options |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.wasm | ||
*.mjs | ||
*.wasm.map |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Overview | ||
|
||
Contains build outputs for *libclang.wasm* and *ffigenpad.wasm*. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:io'; | ||
import 'dart:js_interop'; | ||
import 'dart:js_interop_unsafe'; | ||
|
||
import 'package:logging/logging.dart'; | ||
import 'package:yaml/yaml.dart'; | ||
|
||
import 'memfs.dart'; | ||
import 'src/config_provider.dart'; | ||
import 'src/ffigen.dart'; | ||
|
||
@JS() | ||
external void setLogs(JSObject logs); | ||
|
||
void generate(String yaml) { | ||
final ffigen = FfiGen(logLevel: Level.ALL); | ||
final config = YamlConfig.fromYaml(loadYaml(yaml) as YamlMap); | ||
ffigen.run(config); | ||
} | ||
|
||
void main(List<String> args) { | ||
final logs = <JSObject>[]; | ||
Logger.root.onRecord.listen((record) { | ||
final log = JSObject(); | ||
log.setProperty('level'.toJS, (record.level.value / 100).toJS); | ||
log.setProperty('message'.toJS, record.message.toJS); | ||
|
||
logs.add(log); | ||
}); | ||
IOOverrides.runWithIOOverrides(() { | ||
generate(args.first); | ||
}, MemFSIOOverrides()); | ||
setLogs(logs.toJS); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:convert' as convert; | ||
import 'dart:io'; | ||
import 'dart:js_interop'; | ||
import 'dart:js_interop_unsafe'; | ||
import 'dart:typed_data'; | ||
|
||
// adapted functions from https://emscripten.org/docs/api_reference/Filesystem-API.html#id2 | ||
extension type MemFS(JSObject _) implements JSObject { | ||
external JSArray<JSString> readdir(String path); | ||
external JSUint8Array readFile(String path, [JSObject? opts]); | ||
external void writeFile(String path, String data); | ||
external void unlink(String path); | ||
external void mkdir(String path); | ||
external void rmdir(String path); | ||
external void rename(String oldpath, String newpath); | ||
external String cwd(); | ||
external void chdir(String path); | ||
external JSObject analyzePath(String path, bool dontResolveLastLink); | ||
} | ||
|
||
@JS('FS') | ||
external MemFS get memfs; | ||
|
||
class MemFSDirectory implements Directory { | ||
@override | ||
String path; | ||
|
||
MemFSDirectory(this.path); | ||
|
||
@override | ||
void createSync({bool recursive = false}) { | ||
memfs.mkdir(path); | ||
} | ||
|
||
@override | ||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | ||
} | ||
|
||
class MemFSFile implements File { | ||
@override | ||
String path; | ||
|
||
MemFSFile(this.path); | ||
|
||
@override | ||
MemFSFile get absolute => MemFSFile(path); | ||
|
||
@override | ||
void createSync({bool recursive = false, bool exclusive = false}) { | ||
memfs.writeFile(path, ''); | ||
} | ||
|
||
@override | ||
void deleteSync({bool recursive = false}) { | ||
memfs.unlink(path); | ||
} | ||
|
||
@override | ||
bool existsSync() { | ||
return memfs | ||
.analyzePath(path, false) | ||
.getProperty<JSBoolean>('exists'.toJS) | ||
.toDart; | ||
} | ||
|
||
@override | ||
void writeAsStringSync(String contents, | ||
{FileMode mode = FileMode.write, | ||
convert.Encoding encoding = convert.utf8, | ||
bool flush = false}) { | ||
memfs.writeFile(path, contents); | ||
} | ||
|
||
@override | ||
Uint8List readAsBytesSync() { | ||
return memfs.readFile(path).toDart; | ||
} | ||
|
||
@override | ||
String readAsStringSync({convert.Encoding encoding = convert.utf8}) { | ||
return encoding.decode(readAsBytesSync()); | ||
} | ||
|
||
@override | ||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | ||
} | ||
|
||
class MemFSIOOverrides extends IOOverrides { | ||
@override | ||
MemFSDirectory createDirectory(String path) { | ||
return MemFSDirectory(path); | ||
} | ||
|
||
@override | ||
MemFSFile createFile(String path) { | ||
return MemFSFile(path); | ||
} | ||
|
||
@override | ||
bool fsWatchIsSupported() { | ||
return false; | ||
} | ||
|
||
@override | ||
void setCurrentDirectory(String path) { | ||
memfs.chdir(path); | ||
} | ||
|
||
@override | ||
MemFSDirectory getCurrentDirectory() { | ||
return MemFSDirectory(memfs.cwd()); | ||
} | ||
|
||
@override | ||
MemFSDirectory getSystemTempDirectory() { | ||
return MemFSDirectory('/tmp'); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
/// Generates FFI bindings for a given Library. | ||
library; | ||
|
||
export 'code_generator/binding.dart'; | ||
export 'code_generator/compound.dart'; | ||
export 'code_generator/constant.dart'; | ||
export 'code_generator/enum_class.dart'; | ||
export 'code_generator/func.dart'; | ||
export 'code_generator/func_type.dart'; | ||
export 'code_generator/global.dart'; | ||
export 'code_generator/handle.dart'; | ||
export 'code_generator/imports.dart'; | ||
export 'code_generator/library.dart'; | ||
export 'code_generator/native_type.dart'; | ||
export 'code_generator/objc_block.dart'; | ||
export 'code_generator/objc_built_in_functions.dart'; | ||
export 'code_generator/objc_interface.dart'; | ||
export 'code_generator/objc_methods.dart'; | ||
export 'code_generator/objc_nullable.dart'; | ||
export 'code_generator/objc_protocol.dart'; | ||
export 'code_generator/pointer.dart'; | ||
export 'code_generator/struct.dart'; | ||
export 'code_generator/type.dart'; | ||
export 'code_generator/typealias.dart'; | ||
export 'code_generator/union.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Run dart analyze and dart format on the code on the CI here.