I am trying to create a library in Nim, which ideally could be used in all languages that support C-style libraries, including Nim itself. But it fails, probably beacuse of my Nim inexperience :(
First what I have succeed so far.
First the library
proc lalein*(format:cstring): int {.dynlib, exportc, cdecl.} =
echo "in proc"
format.len
compiled with nim c -d:release -d:strip -d:VERSION=0.1 --opt:size -d:lto --noMain:on --app:lib -o:./target/liblalein.linux.so lalein
And how to use it:
proc lalein(format:cstring): int {.importc, stdcall, dynlib: "./../target/liblalein.linux.so".}
echo "start"
echo lalein("test123")
and compile it as nim c -d:VERSION=0.1 --opt:size -d:lto -o:./target/laleintest.linux laleintest
When run, I correctly get the result "7" as the length of the string.
But now, when I change the library to
proc lalein*(format:cstring): int {.dynlib, exportc, cdecl.} =
echo "in proc"
echo $format
format.len
I get this error:
start
in proc
Traceback (most recent call last)
/usr/src/app/laleintest.nim(3) laleintest
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
fish: Job 1, './target/laleintest.linux 123465' terminated by signal SIGSEGV (Address boundary error)
It would be OK for me, if not even len was correct, but I don't understand why len works, but reading the string itself it doesn't.
I used --gc:arc and it works!
I am a bit confused though, what about memory management. Let's change a bit the library function to
proc lalein*(format:cstring): cstring {.dynlib, exportc, cdecl.} =
"<" & $format & ">"`
This, with arc works! But what happened with the resulting cstring? And even more, if the call wasn't by nim, but by a C application, isn't this a memory leak? And how should be handled?
I'll try to write now a C program that will use it and check. I am more interested what is the "proper" and "correct" way to handle this.
Thanks again.
I used dlopen & dlsym to use the shared Nim procedure.
Everything still works as expected.
But I am still curious about what should be the preferred way not to have a memory leak.
This has cropped up a bit lately, so I decided to write a bit of a longer response: https://peterme.net/dynamic-libraries-in-nim.html
Hopefully that should at least cover the basics. I guess I might add a section about loading libraries in the future. But right now it's time for bed.
Thank you for the reply. Indeed I saw the other post but still my answers weren't answered and I preferred to start a new post.
Thank you for honoring us with your answers!
you might need to manually allocate and free some memory, or create destructors :
My preference would have been to use destructors, since providing a "buffer" could be either "not enough". To be safe usually you need to call the method twice, which is a waste of cycles for me. Destructors might be a bit "dangerous" (in terms that the user won't free up the resource), but is more straight forward.
Thank you for the insights. Now it's much more clear. Indeed there doesn't seem to have a memory leak. I tried to call the method millions of times, while watching memory, and there's no leak.
I also tried to use GC_ref on a cstring, or even string, but this wasn't considered as a reference, but I wrapped it inside a ref object and then I could. When I did that, and make sure that GC_ref is balanced by another GC_unref, everything worked.