Ivan FB 3240ac0080
feat(host): {.ffiHost.} metadata + Go wrapper (increment 5)
5a: record {.ffiHost.} procs in a compile-time registry (FFIHostMeta /
ffiHostRegistry), populated by the macro, so generators can see host fns.

5b: the Go generator emits an idiomatic wrapper over the host C ABI:
- a single //export cgo trampoline backs every host fn; a cgo.Handle in
  userData selects the Go closure;
- the closure runs on a fresh GOROUTINE so the FFI thread is never blocked
  (the non-blocking contract), then answers via <lib>_host_complete by token;
- a per-host `Set<Name>(func(string) (string, error))` method registers it.

Validated end to end with `go run` (examples/host_demo): Go UseToken -> Nim
{.ffi.} handler -> await fetchToken {.ffiHost.} -> Go trampoline -> goroutine
runs the closure -> host_complete -> future resolves on the loop thread ->
"token[TOK-session]" back in Go. Timer's Go output is unchanged (no host fns);
its regenerated .h just gains the always-exported host ABI decls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 23:49:36 +02:00

36 lines
921 B
Makefile

# Build the Nim dylib next to the generated Go package and run the host-callback
# example.
#
# make run # build libhost_demo + run the example
# make clean
#
# The generated package's cgo directives use ${SRCDIR}, so the library only has
# to sit in this directory (-L/-rpath point here). It is compiled from the repo
# root so the vendored Nimble dependencies resolve.
REPO_ROOT := $(abspath ../../..)
NIM_SRC := $(REPO_ROOT)/examples/host_demo/host_demo.nim
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
LIBNAME := libhost_demo.dylib
else
LIBNAME := libhost_demo.so
endif
NIMFLAGS := --mm:orc -d:chronicles_log_level=WARN --app:lib --noMain \
--nimMainPrefix:libhost_demo
.PHONY: all run clean
all: $(LIBNAME)
$(LIBNAME):
cd $(REPO_ROOT) && nim c $(NIMFLAGS) -o:$(CURDIR)/$(LIBNAME) $(NIM_SRC)
run: $(LIBNAME)
cd example && go run .
clean:
rm -f $(LIBNAME) example/example