Call Racket function from C
Asked Answered
R

1

12

I have a Racket module hw.rkt:

#lang racket/base

(provide hw)

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

I would like to write a C program that embeds the Racket runtime and applies the procedure (hw).

There is example code here which demonstrates how to embed the Racket runtime and apply a procedure that is in racket/base, or to read and evaluate an S-expression, but I've had no luck modifying this code to allow access to the (hw) procedure.

This page seems to say that it is possible to do what I want to do by first compiling hw.rkt to hw.c using raco ctool --c-mods, and this works just fine when I try it, but I still can't actually access the (hw) procedure.

If someone could post a complete example program, or simply describe which C functions to use, I would be very appreciative. From there I can figure out the rest.


Editing to provide examples of things I have tried.

I modified the example program to get rid of the "evaluate command line arguments" bit and skip straight to the REPL so that I could experiment. Thus (with "hw.c" the result of running 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);
}

Things that don't work (and their error messages):

Calling (hw) from the REPL

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

Editing the example code

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

Error:

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

(The segfault was probably because I didn't check the value of 'v' before trying to scheme_namespace_require it.)

Editing the example code mk. 2

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

Error:

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

(re: segfault: as above)

Editing the example code mk. 3

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

(as above)

Editing the example code 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);

(as mk. 1, save the segfault)

Editing the example code 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);

Error:

hw: undefined;
 cannot reference undefined identifier
Rupe answered 29/3, 2016 at 14:14 Comment(0)
R
4

Answered by Matthew Flatt here. When using dynamic-require, I needed to quote the name of the module twice, not once. Thanks to Dr. Flatt for their assistance.

Rupe answered 31/3, 2016 at 13:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.