You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit acbb14e
Browse filesBrowse the repository at this point in the historyBrowse files
Add the Python binding: ctypes over the C ABI, driven from asyncio
bindings/python is a pure-ctypes package, so one wheel per platform serves
every Python 3 version. `./codegen` generates it from the IR
(tools/codegen/bindings/src/python.rs): nativeapi/_capi.py mirrors the C ABI
one to one, and each header gets a public module with IntEnum/IntFlag enums,
dataclasses for values and events, and NativeObject classes for handles.
Only _library.py (loading the library) and _runtime.py (ownership,
marshalling, callbacks, the event loop) are hand-written.
CMake builds core into a shared library together with a small event loop
shim, so `await Application.run_async()` pumps the platform loop from
asyncio and tasks, timers and I/O keep running; `Application.run()` blocks
as in the other bindings. scikit-build-core builds the wheel.
Example: python_window_example (a uv project). python-ci.yml lints, tests
and builds the wheel on macOS, Windows and Linux.
Copy file name to clipboardExpand all lines: AGENTS.md
+12-10Lines changed: 12 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# libnativeapi workspace
2
2
3
-
This is the workspace repo (`nativeapi-workspace`, formerly `nativeapi-flutter`) for the [libnativeapi](https://github.com/libnativeapi) project family. All three bindings (`bindings/dart/`, `bindings/rust/`, `bindings/csharp/`), the code generator (`tools/codegen/`), the `./codegen` script, the specs and the shared tooling live directly in this repo (the Rust and C# histories were merged in from `nativeapi-rust` and `nativeapi-csharp`); only `core/` is a git submodule of an independent repository. Work inside `core/` is committed and pushed from that subdirectory; everything else is committed here.
3
+
This is the workspace repo (`nativeapi-workspace`, formerly `nativeapi-flutter`) for the [libnativeapi](https://github.com/libnativeapi) project family. Every binding (`bindings/dart/`, `bindings/rust/`, `bindings/csharp/`, `bindings/js/`, `bindings/python/`), the code generator (`tools/codegen/`), the `./codegen` script, the specs and the shared tooling live directly in this repo (the Rust and C# histories were merged in from `nativeapi-rust` and `nativeapi-csharp`); only `core/` is a git submodule of an independent repository. Work inside `core/` is committed and pushed from that subdirectory; everything else is committed here.
4
4
5
5
## Layout
6
6
@@ -9,8 +9,10 @@ core/ # submodule: nativeapi-core — the C++ core library
9
9
bindings/
10
10
├── dart/ # the Dart binding: nativeapi/, cnativeapi/, nativeapi_flutter/
11
11
├── rust/ # the Rust binding: crates/{nativeapi,cnativeapi}
12
-
└── csharp/ # the C# binding: src/, tests/, NativeAPI.slnx
13
-
examples/ # every binding's example apps, prefixed flutter_*, rust_*, csharp_*
12
+
├── csharp/ # the C# binding: src/, tests/, NativeAPI.slnx
13
+
├── js/ # the JS/TS binding: a Node-API addon (src/) + TypeScript (lib/)
Cargo.toml # cargo workspace root: Rust crates and examples
16
18
tools/codegen/ # in-repo Rust workspace: the code generator
@@ -23,8 +25,8 @@ codegen # Python entry point orchestrating the generators
23
25
## Architecture
24
26
25
27
-`core` — the C++ core library (repo: `nativeapi-core`). The source of truth for the native API surface (windows, tray icons, menus, displays, keyboard, dialogs, storage, etc.) with per-platform implementations (macOS/Windows/Linux).
26
-
-`tools/codegen` — three crates: `shared` (libclang parser, IR, naming), `capi` (C ABI + umbrella header), `bindings` (Rust/Dart/C# generators, consuming the IR JSON emitted by `capi`). Only `capi` depends on libclang. See tools/codegen/README.md.
27
-
-`bindings/*` — language bindings wrapping the core library. All live in this repo and build against the `core/` submodule directly (Rust `build.rs`, the Dart `cnativeapi` package's build hook, the C# native CMake). Only a published package carries its own copy of core, in `cxx_impl/`, which the release workflows vendor and never commit. The Rust binding layers `nativeapi` (safe API) over `cnativeapi` (FFI).
28
+
-`tools/codegen` — three crates: `shared` (libclang parser, IR, naming), `capi` (C ABI + umbrella header), `bindings` (Rust/Dart/C#/JS/Python generators, consuming the IR JSON emitted by `capi`). Only `capi` depends on libclang. See tools/codegen/README.md.
29
+
-`bindings/*` — language bindings wrapping the core library. All live in this repo and build against the `core/` submodule directly (Rust `build.rs`, the Dart `cnativeapi` package's build hook, the C# native CMake, the JS addon's and the Python binding's `CMakeLists.txt`). Only a published package carries its own copy of core, in `cxx_impl/`, which the release workflows vendor and never commit. The Rust binding layers `nativeapi` (safe API) over `cnativeapi` (FFI). The Python binding has no compiled extension: generated `ctypes` code (`nativeapi/_capi.py` plus one module per header) calls a shared library built from core and a small event loop shim, which `Application.run_async()` pumps from asyncio.
28
30
29
31
## Design specs
30
32
@@ -48,12 +50,12 @@ breaks). When one is resolved, edit the spec text itself.
48
50
Always drive the generators through `./codegen` at the workspace root:
-`./codegen check` — read-only verification, non-zero exit when stale (CI mode)
53
55
-`./codegen readme` — copy the shared README sections (`tools/readme/*.md`, e.g. Contributing) into core and every binding; `check` flags drift, `sync` runs it. Edit the snippet, never the copies.
54
56
-`./codegen sync [-m "msg"] [--push]` — full downstream propagation, see below
55
57
56
-
Generated files start with `// AUTO-GENERATED. DO NOT EDIT.` — change the C++ headers in `core/src/` and regenerate instead of editing outputs. Files without that banner are hand-written and never overwritten. The header list (`API_HEADERS`) lives in `tools/codegen/shared/src/lib.rs`.
58
+
Generated files start with `// AUTO-GENERATED. DO NOT EDIT.`(`#` in Python) — change the C++ headers in `core/src/` and regenerate instead of editing outputs. Files without that banner are hand-written and never overwritten. The header list (`API_HEADERS`) lives in `tools/codegen/shared/src/lib.rs`.
57
59
58
60
## Changing the core API
59
61
@@ -68,7 +70,7 @@ It regenerates everything, reruns `bindgen` (Rust raw FFI) and `ffigen` (Dart ra
68
70
Manual follow-ups sync cannot do (details in tools/codegen/README.md):
69
71
70
72
- New handle types need an `IdTypeTag<T>` entry in `core/src/foundation/id_allocator.h` (append only; a miss is a compile error, not silent).
71
-
- Hand-written files in the bindings (exports, re-exports, changelogs, examples) are never touched by the generators. Rust's `pub mod` list is generated (`modules.rs`), and so is Dart's (`nativeapi/lib/src/generated.dart`); `nativeapi_flutter`'s exports are not.
73
+
- Hand-written files in the bindings (exports, re-exports, changelogs, examples) are never touched by the generators. Rust's `pub mod` list is generated (`modules.rs`), and so is Dart's (`nativeapi/lib/src/generated.dart`) and Python's (`nativeapi/__init__.py`); `nativeapi_flutter`'s exports are not.
72
74
73
75
The `core-api-change` skill walks the whole flow, including what to check before `sync` commits.
74
76
@@ -93,8 +95,8 @@ scenarios for *this project's* examples live in [tools/gui/](tools/gui/README.md
93
95
-`core` tracks `branch = main`. Use `make sync` to fast-forward it; `make status` to see dirty state everywhere; `make bump` to stage its pointer.
94
96
- The leanflutter packages built on nativeapi (`tray_manager`, `window_manager`, `launch_at_startup`, …) live in their own repos under github.com/leanflutter and depend on the published `nativeapi`; they are not part of this repo. To try one against local changes, point a `dependency_overrides` entry in that package at `bindings/dart/nativeapi_flutter` (and `nativeapi`, `cnativeapi`) and never commit the override.
95
97
- Commit workspace submodule pointer updates only when the combination is compatible (a known-good snapshot).
96
-
- Examples live in `examples/<binding>_<name>_example` (`flutter_`, `rust_`, `csharp_`), not inside the bindings; a new Flutter or Rust example must also be listed in the root `pubspec.yaml` / `Cargo.toml`, a C# one in `bindings/csharp/NativeAPI.slnx`. Only the pub.dev package examples (`bindings/dart/*/example`) stay inside their package.
97
-
- CI is one workflow per binding (`dart-ci.yml`, `rust-ci.yml`, `csharp-ci.yml`), each running only for changes under its `bindings/<lang>/` and its examples (`examples/flutter_*` for Dart, `examples/rust_*`, `examples/csharp_*`). Release tags are per binding: `v*` publishes the Dart packages (`dart-release.yml`), `rust-v*` publishes the crates (`rust-release.yml`); never push a bare `v*` tag for anything but the Dart packages.
98
+
- Examples live in `examples/<binding>_<name>_example` (`flutter_`, `rust_`, `csharp_`, `js_`, `python_`), not inside the bindings; a new Flutter or Rust example must also be listed in the root `pubspec.yaml` / `Cargo.toml`, a C# one in `bindings/csharp/NativeAPI.slnx`, a JS one in the root `package.json`. A Python example is a standalone uv project whose `pyproject.toml` points `nativeapi` at `../../bindings/python` (`uv run main.py` builds the wheel). Only the pub.dev package examples (`bindings/dart/*/example`) stay inside their package.
99
+
- CI is one workflow per binding (`dart-ci.yml`, `rust-ci.yml`, `csharp-ci.yml`, `js-ci.yml`, `python-ci.yml`), each running only for changes under its `bindings/<lang>/` and its examples (`examples/flutter_*` for Dart, `examples/rust_*`, `examples/csharp_*`, `examples/js_*`, `examples/python_*`). Release tags are per binding: `v*` publishes the Dart packages (`dart-release.yml`), `rust-v*` publishes the crates (`rust-release.yml`); never push a bare `v*` tag for anything but the Dart packages. The Python package is not published yet.
98
100
- The Dart packages `cnativeapi`, `nativeapi` and `nativeapi_flutter` share one version: a release bumps all three pubspecs and CHANGELOGs, because pub.dev's automated publishing matches the tag `v<version>` against each package's own version. `cnativeapi` and `nativeapi` are plain Dart (no Flutter dependency; a build hook compiles core); `nativeapi_flutter` is the Flutter-facing package, holding the widgets, the `dart:ui` conversions and `windowing.dart`, and re-exporting `nativeapi` minus the names that clash with Flutter's.
99
101
- Never commit in a submodule while on a detached HEAD — check out `main` first (`./codegen sync` enforces this).
cd bindings/python && PYTHONPATH=. uvx --with pytest pytest
82
+
```
83
+
84
+
`NATIVEAPI_LIBRARY=/path/to/libnativeapi.dylib` overrides the lookup.
85
+
86
+
## Contributing
87
+
88
+
Development happens in [nativeapi-workspace](https://github.com/libnativeapi/nativeapi-workspace), which holds every binding and the code generator and checks out the core library as a submodule:
Files marked `AUTO-GENERATED. DO NOT EDIT.` are generated from the C++ headers in [nativeapi](https://github.com/libnativeapi/nativeapi-core). To change the API, send a pull request there; maintainers regenerate the bindings.
95
+
96
+
- API requests and native behavior bugs → [nativeapi-core issues](https://github.com/libnativeapi/nativeapi-core/issues)
97
+
- Bugs specific to one binding → [nativeapi-workspace issues](https://github.com/libnativeapi/nativeapi-workspace/issues)
98
+
- Not sure → [nativeapi-core issues](https://github.com/libnativeapi/nativeapi-core/issues)
0 commit comments