Is anyone using the compiler API within a DLL? I'm investigating adding NimScript to a Delphi app by rolling it into a DLL. However I get an AV when I call createInterpreter: If I use the nimrtl then this occurs in createInterpreter at the call to newIdentCache, if I don't use nimrtl it happens at initDefines(conf.symbols). Before I spend any time digging - is this fundamentally a bad idea?
Thanks, Bob
I'm using NimScript in a DLL, but I don't think I did anything special to make it work. I'm compiling with --noMain --app:lib, the default gc, and I'm not using nimrtl. I don't think you need nimrtl if your DLL is the only nim code in the process.
I have no idea what could be wrong, but I can take a look if you post an example somewhere.
@zetashift - thanks I'll take a look
@dsrw - thanks I need nimrtl because there will be other Nim DLLs, but I'd tried anyway and it still crashes. I've cut the code right back to the minimum:
let std = findNimStdLibCompileTime()
let intr = createInterpreter("script.nim", [std])
intr.destroyInterpreter()
I get the AV (the classic C0000005) at createInterpreter - if I comment-out this line it runs fine.
I don't build with --noMain because I use auto-init of the GC. I just tested to check though and it still crashes.
Are you building for 32 or 64-bit?
64 bit. Both the nim dll and the app that loads it are built with mingw.
This sounds more like a GC issue than something specific to the VM. --gc:regions or --gc:orc may help, although I'm sure someone more knowledgeable than myself could get it working with the default gc.
Ok I think I must be missing something because I get the same problem when calling app and DLL are both Nim:
import dynlib
type
scriptProc = proc(): int {.cdecl.}
var
dll: LibHandle
script: scriptProc
echo("Loading scripting DLL...")
dll = loadLib("interpdll.dll")
if dll != nil:
echo "Loaded library interpdll.dll"
let scriptAddr = dll.symAddr("runscript")
if scriptAddr != nil:
echo "Found runscript"
script = cast[scriptProc](scriptAddr)
if script != nil:
let rtn = script()
echo "rtn = " & $rtn
else:
echo "Unable to load runscript() from interpdll.dll"
else:
echo "Unable to load interpdll.dll"
Built with:
c -d:debug --header interptest.nim
DLL:
import compiler / [nimeval, ast, types, llstream, vmdef, vm]
proc runscript*: int {.cdecl, exportc, dynlib.} =
let std = findNimStdLibCompileTime()
let intr = createInterpreter("script.nim", [std])
intr.destroyInterpreter()
return 999
Built with:
c -d:debug --header --app:lib interpdll.nim
Output:
$ ./interptest
Loading scripting DLL...
Loaded library interpdll.dll
Found runscript
Traceback (most recent call last)
H:\Nim\Projects\Misc Tests\Interpreter in DLL\interpdll.nim(5) runscript
C:\Users\rdevine\.choosenim\toolchains\nim-1.4.2\compiler\nimeval.nim(109) createInterpreter
C:\Users\rdevine\.choosenim\toolchains\nim-1.4.2\compiler\idents.nim(114) newIdentCache
C:\Users\rdevine\.choosenim\toolchains\nim-1.4.2\compiler\idents.nim(104) getIdent
C:\Users\rdevine\.choosenim\toolchains\nim-1.4.2\compiler\idents.nim(75) getIdent
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Your example works for me if I build and run it like this:
nim c --app:lib --define:useNimRtl interpdll.nim
nim r --define:useNimRtl interptest.nim
You'll need to build nimrtl.dll from the instructions at https://nim-lang.org/docs/nimc.html#dll-generation and copy it into your working directory.
@dsrw thanks for looking into this - the suggestion in your email re setStackBottom fixed the problem. So my original test DLL with the added three lines for setting the stack now works fine called from Delphi:
compiler / [nimeval, ast, types, llstream, vmdef, vm]
proc runscript*: int {.cdecl, exportc, dynlib.} =
var stackBottom {.volatile.}: pointer
stackBottom = addr(stackBottom)
nimGC_setStackBottom(stackBottom)
writeFile "script.nim", "proc main*: string = \"hello world\""
let std = findNimStdLibCompileTime()
echo std
let intr = createInterpreter("script.nim", [std])
intr.destroyInterpreter()
return 999
Build cmd is:
nim c --app:lib --define:useNimRtl interpdll.nim
Great, I'm glad you got things working. Unfortunately I don't know the Nim GC well enough to say if this is a valid fix, or if it's just a band-aid that will cause problems down the road, but it seems like a step in the right direction at least.
ARC/ORC manages to sidestep most of these problems. I was trying to make some changes to coro recently and ran into all sorts of GC problems, but everything worked perfectly with orc. I'm hoping to move my projects to orc ASAP.