Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the protocol for calling Raku code from C code?

Tags:

raku

Say I have my event-driven TCP communications library in C.

From my Raku application, I can call a function in the C library using NativeCall.

my $server = create-server("127.0.0.1", 4000);

Now, from my callback in C (say onAccept) I want to call out to a Raku function in my application (say on-accept(connection) where connection will be a pointer to a C struct).

So, how can I do that: call my Raku function on-accept from my C function onAccept ?

ps. I tried posting using a simple title "How to call Raku code from C code", but for whatever reason stackoverflow.com wouldn't let me do it. Because of that I concocted this fancy title.

I was creating a 32-bit DLL. We have to explicitly tell CMake to configure a 64-bit build.

cmake -G "Visual Studio 14 2015 Win64" ..

Anyway, now that the code runs, it's not really what I asked for, because the callback is still in C.

It seems that what I asked for it's not really possible.

I tried to use the approach suggested by Haakon, though I'm afraid I don't understand how it would work.

I'm in Windows, and unfortunately, Raku can't find my dlls, even if I put them in C:\Windows\System32. It finds "msvcrt" (C runtime), but not my dlls.

The dll code (Visual Studio 2015).

#include <stdio.h>

#define EXPORTED __declspec(dllexport)

typedef int (*proto)(const char*);

proto raku_callback;

extern EXPORTED void set_callback(proto);
extern EXPORTED void foo(void);

void set_callback(proto arg)
{
  printf("In set_callback()..\n");
  raku_callback = arg;
}

void foo(void)
{
  printf("In foo()..\n");
  int res = raku_callback("hello");
  printf("Raku return value: %d\n", res);
}

Cmake code for the

CMAKE_MINIMUM_REQUIRED (VERSION 3.1)
add_library (my_c_dll SHARED my_c_dll.c)

Raku code.

use v6.d;

use NativeCall;

sub set_callback(&callback (Str --> int32))
  is native("./my_c_dll"){ * }

sub foo()
  is native("./my_c_dll"){ * }

sub callback(Str $str --> Int) {
  say "Raku callback.. got string: {$str} from C";
  return 32;
}

## sub _getch() returns int32 is native("msvcrt") {*};
## print "-> ";
## say "got ", _getch();

set_callback(&callback);
# foo();

When I run

$ raku test-dll.raku
Cannot locate native library '(null)': error 0xc1
  in method setup at D:\tools\raku\share\perl6\core\sources
    \947BDAB9F96E0E5FCCB383124F923A6BF6F8D76B (NativeCall) line 298
  in block set_callback at D:\tools\raku\share\perl6\core\sources
     \947BDAB9F96E0E5FCCB383124F923A6BF6F8D76B (NativeCall) line 594
  in block <unit> at test-dll.raku line 21

Raku version.

$ raku -v
This is Rakudo version 2020.05.1 built on MoarVM version 2020.05
implementing Raku 6.d.
like image 298
zentrunix Avatar asked Feb 19 '21 22:02

zentrunix


1 Answers

Another approach could be to save a callback statically in the C library, for example (libmylib.c):

#include <stdio.h>

static int (*raku_callback)(char *arg);

void set_callback(int (*callback)(char * arg)) {
    printf("In set_callback()..\n");
    raku_callback = callback;
}

void foo() {
    printf("In foo()..\n");
    int res = raku_callback("hello");
    printf("Raku return value: %d\n", res);
}

Then from Raku:

use v6;
use NativeCall;

sub set_callback(&callback (Str --> int32)) is native('./libmylib.so') { * }
sub foo() is native('./libmylib.so') { * }

sub callback(Str $str --> Int) {
    say "Raku callback.. got string: {$str} from C";
    return 32;
}

set_callback(&callback);
foo();

Output:

In set_callback()..
In foo()..
Raku callback.. got string: hello from C
Raku return value: 32
like image 100
Håkon Hægland Avatar answered Sep 28 '22 10:09

Håkon Hægland