mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-08-05 06:23:19 +00:00
41 lines
2.7 KiB
Markdown
41 lines
2.7 KiB
Markdown
# skeleton — new-library template
|
|
|
|
A minimal, compilable nim-ffi library: a constructor, one async method, a library-initiated event, and a destructor, plus a nimble file and checked-in C++ bindings. Copy this directory instead of reverse-engineering `examples/timer/` (which is a feature tour, not a starting point).
|
|
|
|
## What's here
|
|
|
|
- `skeleton.nim` — the library. Every nim-ffi lib needs these four pieces, and nothing else:
|
|
- `declareLibrary("skeleton", Skeleton)` — names the lib and its state object; must come before any FFI annotation.
|
|
- `{.ffiCtor.}` constructor returning `Future[Result[T, string]]`.
|
|
- one `{.ffi.}` async method, same return contract.
|
|
- `{.ffiEvent.}` for a library-initiated callback.
|
|
- `{.ffiDtor.}` destructor.
|
|
- `genBindings()` as the **last** top-level call.
|
|
- `skeleton.nimble` — `build` and `genbindings_cpp` tasks.
|
|
- `cpp_bindings/` — generated C++ bindings, checked in and diff-verified by CI (`nimble check_bindings`).
|
|
|
|
## Copy-rename checklist
|
|
|
|
Pick your library name in two casings: a snake_case wire name (e.g. `my_lib`) and its PascalCase state type (e.g. `MyLib`).
|
|
|
|
1. Copy the directory: `cp -r examples/skeleton examples/my_lib`
|
|
2. Rename both files: `skeleton.nim` → `my_lib.nim`, `skeleton.nimble` → `my_lib.nimble`.
|
|
3. In `my_lib.nim`, replace every `skeleton` → `my_lib` and `Skeleton` → `MyLib`. That covers `declareLibrary("my_lib", MyLib)`, the state type, and the `myLibCreate` / `myLibHello` / `my_lib_destroy` proc names. Rename the request/response/event/config types to whatever your API needs.
|
|
4. In `my_lib.nimble`, update `packageName`, `description`, and every `libskeleton` → `libmy_lib` / `skeleton.nim` → `my_lib.nim`. The `--nimMainPrefix:libmy_lib` must match your `declareLibrary` name.
|
|
5. Regenerate bindings: `cd examples/my_lib && nimble genbindings_cpp` (add `-d:targetLang=rust` / `c` / `c_abi` variants as needed — see the root `ffi.nimble` for the full flag set).
|
|
6. If you keep the library long-term, wire it into the root `ffi.nimble` `check_bindings` task the same way `skeleton` is, so CI catches binding drift.
|
|
|
|
## Contracts worth remembering
|
|
|
|
- Every `{.ffi.}` / `{.ffiCtor.}` returns `Future[Result[T, string]]`: `return ok(value)` on success, `return err("reason")` on failure.
|
|
- A `{.ffi.}` method takes the state object as its **first** parameter.
|
|
- The dtor's exported symbol name (`skeleton_destroy`) avoids the camelCase→snake_case derivation and reads naturally in C; name yours the same way.
|
|
- `genBindings()` reads compile-time registries populated by the pragmas above it. Anything declared after it — or in a module imported after it — is silently missing from the output.
|
|
|
|
## Build & generate
|
|
|
|
```sh
|
|
cd examples/skeleton
|
|
nimble genbindings_cpp # writes cpp_bindings/
|
|
```
|