I'm trying to use Nim's FFI to import a proc from a compiled Nim library that returns an object Foo. I want to create a Foo object from the pointer returned by this imported proc.
I get an illegal storage access error. This seems like it should be simple, what am I doing wrong?
## nim c --define:release --app:lib --noMain --out:foo.o "nim_exported.nim"
type
Foo* = object
name*: string
number*: int
proc returnFoo*(): Foo {.exportc, cdecl, dynlib.} =
result = Foo(name: "nim", number: 1)
import dynlib
type
Foo = object
name: string
number: int
FooPtr = ptr Foo
let lib = loadLib("foo.o")
type
procFoo = proc(): FooPtr {.gcsafe, stdcall.}
let newFoo = cast[procFoo](lib.symAddr("returnFoo"))
let x = newFoo()
echo x[]
result = addr e
Cannot work, you return a pointer to a location on the stack that is about to disappear.
and you'll need to provide another proc to dealloc the memory
I re-read The Nim memory model and I think I see why the first example wouldn't have worked (when the stack unwinds addr e no longer points to e).
I updated the example @shirleyquirk provided but I still have a read from nil error. This is confusing because create allocates a memory block on the heap. Also wondering if this should be done using ref objects instead?
## nim c --define:release --app:lib --noMain --out:foo.o "nim_exported.nim"
type
Foo* = object
name*: string
number*: int
FooPtr* = ptr Foo
proc returnFoo*(): FooPtr {.exportc, cdecl, dynlib.} =
result = create Foo
result[] = Foo(name: "nim", number: 1)
import dynlib
type
Foo = object
name: string
number: int
FooPtr = ptr Foo
let lib = loadLib("foo.o")
type
procFoo = proc(): FooPtr {.gcsafe, stdcall.}
let newFoo = cast[procFoo](lib.symAddr("returnFoo"))
let x = newFoo()
echo x[]
foo.nim:
##nim c --app:lib foo.nim
#by default creates 'libfoo.so'
type
Foo* = object
name*: string
number*: int
proc newFoo*(): ptr Foo {.exportc, cdecl, dynlib.} =
result = create Foo
result[] = Foo(name: "nim", number: 1)
main.nim:
##nim c -r main.nim
import dynlib
type
Foo = object
name: string
number: int
FooProc = proc(): ptr Foo {.nimcall, gcsafe.}
let lib = loadLib("./libfoo.so")
if lib.isNil:
echo "Error loading lib"
quit()
let newFoo = cast[FooProc](lib.symAddr("newFoo"))
if newFoo.isNil:
echo "Failed to find newFoo in lib"
quit()
let x = newFoo()
if x.isNil:
echo "newFoo() returned nil"
quit()
echo x[]