Is it possible to load a nim dylib dynamically from another module?
As a test, I have foo:
proc getDefn() : int {.exportc cdecl.} =
return 1
and run nim c --app:lib foo.nim.
In 2nd module I have
import dynlib
type
InitProc = (proc() {.cdecl.})
GetDefn = (proc(): int {.cdecl.})
let fn = "libfoo.dylib"
let libHandle = loadLib(fn)
let init = cast[InitProc]( checkedSymAddr(libHandle, "NimMain"))
init()
let test = cast[GetDefn](checkedSymAddr(libHandle, "getDefn")
echo $test()
But it fails with SIGBUS: Illegal storage access. (Attempt to read from nil?) on the last statement. Here example code which I use on OSX:
# plugin.nim
var data = 0
{.push dynlib exportc.}
proc setup*(num:int) =
data = num
echo "Plugin Setup!"
proc getData*: int = data
{.pop.}
# plugin.nim.cfg
app:lib
# app.nim
import dynlib
type
SetupProc = proc(num:int) {.nimcall.}
GetDataProc = proc(): int {.nimcall.}
proc testPlugin(path:string) =
let lib = loadLib(path)
if lib != nil:
let setupAddr = lib.symAddr("setup")
let getDataAddr = lib.symAddr("getData")
if setupAddr != nil and getDataAddr != nil:
let setup = cast[SetupProc](setupAddr)
let getData = cast[GetDataProc](getDataAddr)
setup(123)
echo "Plugin Data: ", getData()
unloadLib(lib)
when defined(macosx):
testPlugin("./libplugin.dylib") # osx path
else:
testPlugin("./libplugin.so") # unix path
Ok thanks, everyone! My example was extracted from a larger code block, and the function I was trying to call was being spit out by a macro; it turned out I hadn't wrapped everything I needed to in the right pragmas. Now I have it working.
What is the right way to do this portably, btw? Should I use cdecl, or nimcall as @OderWat suggests? Or does it not matter as long as I am consistent? I see there is a DynlibFormat constant in os ... presumably this is what I should use to avoid a case stmt?