diff --git a/examples/timer/c_bindings/my_timer.h b/examples/timer/c_bindings/my_timer.h index cd50e82..d5270b0 100644 --- a/examples/timer/c_bindings/my_timer.h +++ b/examples/timer/c_bindings/my_timer.h @@ -111,6 +111,8 @@ int my_timer_schedule(void *ctx, FFICallBack callback, void *userData, JobSpec j int my_timer_destroy(void *ctx); +// Native event payloads — cast the callback's msg accordingly: +// "on_echo_fired" -> const EchoEvent * uint64_t my_timer_add_event_listener(void *ctx, const char *eventName, FFICallBack callback, void *userData); int my_timer_remove_event_listener(void *ctx, uint64_t listenerId); diff --git a/ffi.nimble b/ffi.nimble index d6b3215..effec1d 100644 --- a/ffi.nimble +++ b/ffi.nimble @@ -146,19 +146,22 @@ task genbindings_rust, "Generate Rust bindings for the timer example": " -d:ffiSrcPath=../timer.nim" & " -o:/dev/null examples/timer/timer.nim" -task genbindings_c, "Generate C bindings for the timer example": - exec "nim c " & nimFlagsOrc & - " --app:lib --noMain --nimMainPrefix:libmy_timer" & - " -d:ffiGenBindings -d:targetLang=c" & - " -d:ffiOutputDir=examples/timer/c_bindings" & - " -d:ffiSrcPath=../timer.nim" & - " -o:/dev/null examples/timer/timer.nim" - exec "nim c " & nimFlagsRefc & - " --app:lib --noMain --nimMainPrefix:libmy_timer" & - " -d:ffiGenBindings -d:targetLang=c" & - " -d:ffiOutputDir=examples/timer/c_bindings" & - " -d:ffiSrcPath=../timer.nim" & - " -o:/dev/null examples/timer/timer.nim" +# `mode` selects the ABI to emit: "native", "cbor", or "both" (-d:ffiMode). +proc genC(mode: string) = + for flags in [nimFlagsOrc, nimFlagsRefc]: + exec "nim c " & flags & " --app:lib --noMain --nimMainPrefix:libmy_timer" & + " -d:ffiGenBindings -d:targetLang=c -d:ffiMode=" & mode & + " -d:ffiOutputDir=examples/timer/c_bindings -d:ffiSrcPath=../timer.nim" & + " -o:/dev/null examples/timer/timer.nim" + +task genbindings_c, "Generate C bindings (native + CBOR) for the timer example": + genC("both") + +task genbindings_c_native, "Generate only the native C bindings (.h)": + genC("native") + +task genbindings_c_cbor, "Generate only the CBOR C bindings (_cbor.h)": + genC("cbor") task genbindings_go, "Generate Go (cgo) bindings for the timer example": exec "nim c " & nimFlagsOrc & diff --git a/ffi/codegen/c.nim b/ffi/codegen/c.nim index 369b5d1..06b3744 100644 --- a/ffi/codegen/c.nim +++ b/ffi/codegen/c.nim @@ -167,8 +167,13 @@ proc generateCHeader*( lines.add("") # `declareLibrary` always exports the listener-registration ABI. The native - # header advertises the native listener: the callback's msg is a typed - # `const *` (cast it), not CBOR. + # listener delivers the payload as a typed struct: on RET_OK the callback's + # `msg` is a `const *` (cast it; valid only for the callback), keyed by + # the registered event name below. + if events.len > 0: + lines.add("// Native event payloads — cast the callback's msg accordingly:") + for e in events: + lines.add("// \"" & e.wireName & "\" -> const " & e.payloadTypeName & " *") lines.add( "uint64_t " & libName & "_add_event_listener(void *ctx, const char *eventName, FFICallBack callback, void *userData);" @@ -401,12 +406,14 @@ proc generateCBindings*( nimSrcRelPath: string, events: seq[FFIEventMeta] = @[], ) = - # Emit both ABIs so consumers can choose per call site: the native (zero-copy, - # same-process) one and the CBOR (boundary-crossing / generic) one. - writeFile( - outputDir / (libName & ".h"), generateCHeader(procs, types, libName, events) - ) - writeFile( - outputDir / (libName & "_cbor.h"), - generateCborCHeader(procs, types, libName, events), - ) + # Emit the ABI(s) selected by -d:ffiMode (default both): the native (zero-copy, + # same-process) header and/or the CBOR (boundary-crossing / generic) one. + if ffiEmitNative(): + writeFile( + outputDir / (libName & ".h"), generateCHeader(procs, types, libName, events) + ) + if ffiEmitCbor(): + writeFile( + outputDir / (libName & "_cbor.h"), + generateCborCHeader(procs, types, libName, events), + ) diff --git a/ffi/codegen/meta.nim b/ffi/codegen/meta.nim index 230919a..16d5189 100644 --- a/ffi/codegen/meta.nim +++ b/ffi/codegen/meta.nim @@ -49,6 +49,16 @@ var currentLibName* {.compileTime.}: string # Target language for binding generation; override with -d:targetLang=cpp const targetLang* {.strdefine.} = "rust" +# Which ABI(s) to emit: "native" (zero-serialization C structs), "cbor" +# (inter-process), or "both" (default). Override with -d:ffiMode=native. +const ffiMode* {.strdefine.} = "both" + +func ffiEmitNative*(): bool = + ffiMode == "native" or ffiMode == "both" + +func ffiEmitCbor*(): bool = + ffiMode == "cbor" or ffiMode == "both" + # Output directory for generated bindings; set with -d:ffiOutputDir=path/to/dir const ffiOutputDir* {.strdefine.} = ""