mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-08-05 06:23:19 +00:00
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 returningFuture[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—buildandgenbindings_cpptasks.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).
- Copy the directory:
cp -r examples/skeleton examples/my_lib - Rename both files:
skeleton.nim→my_lib.nim,skeleton.nimble→my_lib.nimble. - In
my_lib.nim, replace everyskeleton→my_libandSkeleton→MyLib. That coversdeclareLibrary("my_lib", MyLib), the state type, and themyLibCreate/myLibHello/my_lib_destroyproc names. Rename the request/response/event/config types to whatever your API needs. - In
my_lib.nimble, updatepackageName,description, and everylibskeleton→libmy_lib/skeleton.nim→my_lib.nim. The--nimMainPrefix:libmy_libmust match yourdeclareLibraryname. - Regenerate bindings:
cd examples/my_lib && nimble genbindings_cpp(add-d:targetLang=rust/c/c_abivariants as needed — see the rootffi.nimblefor the full flag set). - If you keep the library long-term, wire it into the root
ffi.nimblecheck_bindingstask the same wayskeletonis, so CI catches binding drift.
Contracts worth remembering
- Every
{.ffi.}/{.ffiCtor.}returnsFuture[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
cd examples/skeleton
nimble genbindings_cpp # writes cpp_bindings/