3

I am trying to call Nim code from C++. Specifically, a function that takes an anonymous function.

I have the following code in Nim:

proc test*(a: proc()) {.exportc.} = a()

which I compile to a static library. I then link it to my C++ executable and attempt to define the function with

extern "C" test(void a(void);

and call it with

void anon() { printf("hello"); }
...
test(anon)

Everything compiles fine, but when I run the program, it crashes.

Grzegorz Adam Hankiewicz
  • 7,349
  • 1
  • 36
  • 78
Mnenmenth
  • 45
  • 1
  • 7

1 Answers1

6

By default, Nim will compile the anonymous proc types as closures represented by a pair of a C function pointer and a void pointer to a structure holding all of the local variables captured by the closure. It will look like this in the generated code:

typedef struct {
N_NIMCALL_PTR(void, ClP_0) (void* ClE_0);
void* ClE_0;
} tyProc_XXXXXX;

So, to solve the problem you must modify the extern "C" definition of the test function in the C code to accept a compatible structure type. Alternatively, you can ask Nim to compile the proc argument to a regular C function by adding the cdecl pragma to the proc type:

proc test*(a: proc() {.cdecl.}) {.exportc.} = a()

For the full list of calling conventions supported by Nim, check out the section on proc types in the Nim manual.

zah
  • 5,314
  • 1
  • 34
  • 31
  • Is there any way to assign a `{.cdecl.}` proc to a `{.closure.}` proc? I'm trying to assign the proc in the arguments to a type member proc from the base nim library – Mnenmenth Mar 02 '18 at 18:01
  • 1
    You can use `{.nimcall.}` instead of `cdecl` to achieve the same effect and preserve compatibility with regular Nim procs. Alternatively, you can always wrap any Nim proc in a simple forwarding proc with a different calling convention. – zah Mar 03 '18 at 10:23