0

I have a C library clib.c with this function

int hi(char* hello) { return 900; }

compiled as:

gcc clib.c -o clib.so --shared -fPIC

I'm consuming this in a Nim libray called 'nlib.nim`:

proc hi*(hello: cstring): cint {.cdecl, importc: "hi", dynlib: "./clib.so".}
proc hi2*(hello: cstring): cint {.cdecl, exportc.} = return hi(hello)

complied as:

nim c --app:lib --noMain -o:nlib.so nlib.nim

If I call the hi2 function directly in Nim, it returns 900, perfectly. But if I call it from NodeJS via FFI:

var ffi = require('ffi');
var lib = ffi.Library('./nlib.so', { 'hi2' : [ "int", ["string"] ] });
console.log(lib.hi2("hey"));

I get a Segmentation fault (core dumped).

David Broderick
  • 112
  • 1
  • 8

2 Answers2

2

There are two problems in your code:

  1. You shouldn't have used --noMain.

    During the initialization of the nlib.so library, it will load the symbols from clib.so dynamically (i.e. with dlopen and dlsym). Specifying --noMain interferes with this process and you should do it only if you have a specific goal in mind.

  2. You should initialize the Nim GC when calling Nim from other host languages.

    This is usually done by calling setupForeignThreadGc. To make this available, you should compile with --threads:on.

So, the final solution looks like this:

# nlib.nim

proc hi*(hello: cstring): cint {.cdecl, importc: "hi", dynlib: "./clib.so".}

proc nlib_init* {.cdecl, exportc.} =
  setupForeignThreadGc()

proc nlib_hi*(hello: cstring): cint {.cdecl, exportc.} =
  return hi(hello)

Compile with:

nim c --threads:on --app:lib -o:nlib.so nlib.nim

Then in node.js, we have:

# nlib.js

var ffi = require('ffi');

var nlib = ffi.Library('./nlib.so', {
  'nlib_init': [ "void", []],
  'nlib_hi': [ "int", ["string"] ]
});

nlib.nlib_init()
console.log(nlib.nlib_hi("hey"));

Execute with:

node nlib.js

Output:

900
zah
  • 5,314
  • 1
  • 34
  • 31
0

You cannot use the FFI at the same time in JS and C. Quoting from Nim in Action:

It’s important to note that the FFI allows you to interface with C, C++, and Objective-C libraries in the same application, but you can’t interface with both C and Java-Script libraries at the same time. This is because C++ and Objective-C are both backward compatible with C, whereas JavaScript is a completely different language.

pietroppeter
  • 1,433
  • 13
  • 30
  • Actually, it works fine. I just should have removed '--noMain'. – David Broderick Oct 16 '18 at 08:41
  • Ok, good to know! I guess than that the quote from Nim in action does not apply to this example, right? In fact you are not trying to use Nim’s FFI with both C’s and JS libraries but you are using JS FFI to load a separate dynamic library that you compiled with Nim... – pietroppeter Oct 16 '18 at 09:10