从 C 调用 Racket 函数

Posted

技术标签:

【中文标题】从 C 调用 Racket 函数【英文标题】:Call Racket function from C 【发布时间】:2016-07-17 03:55:05 【问题描述】:

我有一个 Racket 模块 hw.rkt:

#lang racket/base

(provide hw)

(define (hw) (displayln "Hello, world!"))

我想编写一个嵌入 Racket 运行时并应用程序(hw) 的 C 程序。

有示例代码 here 演示了如何嵌入 Racket 运行时并应用 racket/base 中的过程,或者读取和评估 S 表达式,但我没有运气修改此代码以允许访问(hw) 过程。

This page 似乎在说可能首先使用raco ctool --c-mods 将 hw.rkt 编译为 hw.c 来做我想做的事情,当我尝试时这工作得很好它,但我仍然无法真正访问(hw) 过程。

如果有人可以发布一个完整的示例程序,或者简单地描述要使用哪些 C 函数,我将非常感激。从那里我可以弄清楚其余的。


编辑以提供我尝试过的事情的示例。

我修改了示例程序以摆脱“评估命令行参数”位并直接跳到 REPL 以便我可以进行实验。因此(使用“hw.c”运行raco ctool --c-mods hw.c ++libs racket/base hw.rkt的结果):

#define MZ_PRECISE_GC
#include "scheme.h"

#include "hw.c"

static int run(Scheme_Env *e, int argc, char *argv[])

  Scheme_Object *curout = NULL, *v = NULL, *a[2] = NULL, NULL;
  Scheme_Config *config = NULL;
  int i;
  mz_jmp_buf * volatile save = NULL, fresh;

  MZ_GC_DECL_REG(8);
  MZ_GC_VAR_IN_REG(0, e);
  MZ_GC_VAR_IN_REG(1, curout);
  MZ_GC_VAR_IN_REG(2, save);
  MZ_GC_VAR_IN_REG(3, config);
  MZ_GC_VAR_IN_REG(4, v);
  MZ_GC_ARRAY_VAR_IN_REG(5, a, 2);

  MZ_GC_REG();

  declare_modules(e);

  v = scheme_intern_symbol("racket/base");
  scheme_namespace_require(v);

  config = scheme_current_config();
  curout = scheme_get_param(config, MZCONFIG_OUTPUT_PORT);

  save = scheme_current_thread->error_buf;
  scheme_current_thread->error_buf = &fresh;
  if (scheme_setjmp(scheme_error_buf)) 
    scheme_current_thread->error_buf = save;
    return -1; /* There was an error */
   else 
    /* read-eval-print loop, uses initial Scheme_Env: */
    a[0] = scheme_intern_symbol("racket/base");
    a[1] = scheme_intern_symbol("read-eval-print-loop");
    v = scheme_dynamic_require(2, a);
    scheme_apply(v, 0, NULL);
    scheme_current_thread->error_buf = save;
  

  MZ_GC_UNREG();

  return 0;


int main(int argc, char *argv[])

  return scheme_main_setup(1, run, argc, argv);

不起作用的事情(及其错误消息):

从 REPL 调用 (hw)

hw: undefined:
 cannot reference undefined identifier
  context...:
   /usr/local/share/racket/collects/racket/private/misc.rkt:87:7

((dynamic-require 'hw 'hw))

standard-module-name-resolver: collection not found
  for module path: hw
  collection: "hw"
  in collection directories:
  context...:
   show-collection-err
   standard-module-name-resolver
   /usr/local/share/racket/collects/racket/private/misc.rkt:87:7

((dynamic-require "hw.rkt" 'hw))

standard-module-name-resolver: collection not found
  for module path: racket/base/lang/reader
  collection: "racket/base/lang"
  in collection directories:
  context...:
   show-collection-err
   standard-module-name-resolver
   standard-module-name-resolver
   /usr/local/share/racket/collects/racket/private/misc.rkt:87:7

编辑示例代码

v = scheme_intern_symbol("racket/base");
scheme_namespace_require(v);
v = scheme_intern_symbol("hw");
scheme_namespace_require(v);

错误:

standard-module-name-resolver: collection not found
  for module path: hw
  collection: "hw"
  in collection directories:
  context...:
   show-collection-err
   standard-module-name-resolver
SIGSEGV MAPERR sicode 1 fault on addr 0xd0
Aborted

(段错误可能是因为我在尝试scheme_namespace_require之前没有检查'v'的值。)

编辑示例代码 mk. 2

v = scheme_intern_symbol("racket/base");
scheme_namespace_require(v);
v = scheme_intern_symbol("hw.rkt");
scheme_namespace_require(v);

错误:

hw.rkt: bad module path
  in: hw.rkt
  context...:
   standard-module-name-resolver
SIGSEGV MAPERR sicode 1 fault on addr 0xd0
Aborted

(re: segfault: 同上)

编辑示例代码 mk. 3

v = scheme_intern_symbol("racket/base");
scheme_namespace_require(v);
v = scheme_intern_symbol("./hw.rkt");
scheme_namespace_require(v);

(如上)

编辑示例代码 mk. 4

/* read-eval-print-loop, uses initial Scheme_Env: */
a[0] = scheme_intern_symbol("hw");
a[1] = scheme_intern_symbol("hw");
v = scheme_dynamic_require(2, a);

(如 mk.1,保存段错误)

编辑示例代码 mk. 5

/* read-eval-print loop, uses initial Scheme_Env: */
a[0] = scheme_intern_symbol("hw");
a[1] = scheme_eval(a[0], e);
scheme_apply(a[1], 0, NULL);

错误:

hw: undefined;
 cannot reference undefined identifier

【问题讨论】:

【参考方案1】:

由 Matthew Flatt here 回答。使用dynamic-require 时,我需要引用模块名称两次,而不是一次。感谢 Flatt 博士的帮助。

【讨论】:

以上是关于从 C 调用 Racket 函数的主要内容,如果未能解决你的问题,请参考以下文章

Racket 博士有自动完成功能吗?

Scheme中的递归和调用堆栈

重新定义 Racket 中的语法以接受四元数

使用 lexyacc 在 racket 中实现一个类似 C 语言的程序。

Racket如何生成二进制的可执行文件?

从matlab调用c函数