从 C 代码调用 Raku 代码的协议是什么?

zen*_*nix 14 raku

假设我在 C 中有我的事件驱动的 TCP 通信库。

在我的 Raku 应用程序中,我可以使用 NativeCall 调用 C 库中的函数。

my $server = create-server("127.0.0.1", 4000);
Run Code Online (Sandbox Code Playgroud)

现在,从我用C回调(say onAccept)我想调出在我的应用程序乐功能(说on-accept(connection)那里connection将是一个指向C结构)。

那么,我该怎么做:on-accept从我的 C 函数调用我的 Raku函数onAccept

附:我尝试使用一个简单的标题“如何从 C 代码调用 Raku 代码”进行发布,但无论出于何种原因,stackoverflow.com 都不允许我这样做。正因为如此,我编造了这个花哨的标题。

我正在创建一个 32 位 DLL。我们必须明确告诉 CMake 配置 64 位构建。

cmake -G "Visual Studio 14 2015 Win64" ..
Run Code Online (Sandbox Code Playgroud)

无论如何,现在代码运行了,这不是我所要求的,因为回调仍然在 C 中。

我所要求的似乎不太可能。

我尝试使用 Haakon 建议的方法,但恐怕我不明白它是如何工作的。

我在 Windows 中,不幸的是,Raku 找不到我的 dll,即使我将它们放在 C:\Windows\System32 中。它找到“msvcrt”(C 运行时),但没有找到我的 dll。

dll 代码(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);
}
Run Code Online (Sandbox Code Playgroud)

的 Cmake 代码

CMAKE_MINIMUM_REQUIRED (VERSION 3.1)
add_library (my_c_dll SHARED my_c_dll.c)
Run Code Online (Sandbox Code Playgroud)

乐库代码。

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();
Run Code Online (Sandbox Code Playgroud)

当我跑

$ 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
Run Code Online (Sandbox Code Playgroud)

乐库版。

$ raku -v
This is Rakudo version 2020.05.1 built on MoarVM version 2020.05
implementing Raku 6.d.
Run Code Online (Sandbox Code Playgroud)

Håk*_*and 12

另一种方法是在 C 库中静态保存回调,例如 ( 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);
}
Run Code Online (Sandbox Code Playgroud)

然后从乐:

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();
Run Code Online (Sandbox Code Playgroud)

输出

In set_callback()..
In foo()..
Raku callback.. got string: hello from C
Raku return value: 32
Run Code Online (Sandbox Code Playgroud)


jjm*_*elo 6

Raku是一种编译语言;根据您的实现,它将被编译为MoarVM、 JVM 或 Javascript。通过编译,Raku 代码在相应的虚拟机中变成字节码。所以它实际上从来都不是二进制代码。

然而,Raku 代码似乎以某种方式巧妙地组织起来,即对象实际上是指向 C 端点的指针,正如Haakon Hagland 的 回答所证明的那样

WRT 到您的最新问题,请记住,您调用的不是路径,而是转换为本地共享库名称并使用本地库路径约定来查找它们的名称(在 Windows 上为“PATH”) )。因此,如果没有找到它,请向其添加本地路径,只需将 DLL 复制到搜索目录之一即可。

  • 在我的问题中使用的情况下,连接也将由 C 代码处理,但是,是的,我认为你是对的,回调(尤其是多线程应用程序生成的异步回调)必须由 C 代码处理... Raku 代码和 C 代码之间的交互必须序列化(如非多线程),但我认为没有其他方法可以做到这一点(事实上,我相信这就是 node.js 的工作原理)...感谢您的输入 (2认同)