2 Embedding into a Program (CS)🔗

To embed Racket CS in a program, follow these steps:

Racket values may be moved or garbage collected any time that racket_... functions are used to run Racket code. Do not retain a reference to any Racket value across such a call.

For example, the following is a simple embedding program that runs a module "run.rkt", assuming that "run.c" is created as

  raco ctool --c-mods run.c "run.rkt"

to generate "run.c", which encapsulates the compiled form of "run.rkt" and all of its transitive imports (so that they need not be found separately a run time). Copies of "petite.boot", "scheme.boot", and "racket.boot" must be in the current directory on startup.

"main.c"

  #include <string.h>

  #include "chezscheme.h"

  #include "racketcs.h"

  

  #include "run.c"

  

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

  {

    racket_boot_arguments_t ba;

  

    memset(&ba, 0, sizeof(ba));

  

    ba.boot1_path = "./petite.boot";

    ba.boot2_path = "./scheme.boot";

    ba.boot3_path = "./racket.boot";

  

    ba.exec_file = argv[0];

  

    racket_boot(&ba);

  

    declare_modules();

  

    ptr mod = Scons(Sstring_to_symbol("quote"),

                    Scons(Sstring_to_symbol("run"),

                          Snil));

  

    racket_dynamic_require(mod, Sfalse);

  

    return 0;

  }

As another example, the following is a simple embedding program that evaluates all expressions provided on the command line and displays the results, then runs a read-eval-print loop, all using racket/base. Run

  raco ctool --c-mods base.c ++lib racket/base

to generate "base.c", which encapsulates racket/base and all of its transitive imports.

"main.c"

  #include <string.h>

  #include "chezscheme.h"

  #include "racketcs.h"

  

  #include "base.c"

  

  static ptr to_bytevector(char *s);

  

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

  {

    racket_boot_arguments_t ba;

  

    memset(&ba, 0, sizeof(ba));

  

    ba.boot1_path = "./petite.boot";

    ba.boot2_path = "./scheme.boot";

    ba.boot3_path = "./racket.boot";

  

    ba.exec_file = argv[0];

  

    racket_boot(&ba);

  

    declare_modules();

  

    racket_namespace_require(Sstring_to_symbol("racket/base"));

  

    {

      int i;

      for (i = 1; i < argc; i++) {

        ptr e = to_bytevector(argv[i]);

        e = Scons(Sstring_to_symbol("open-input-bytes"),

                  Scons(e, Snil));

        e = Scons(Sstring_to_symbol("read"), Scons(e, Snil));

        e = Scons(Sstring_to_symbol("eval"), Scons(e, Snil));

        e = Scons(Sstring_to_symbol("println"), Scons(e, Snil));

  

        racket_eval(e);

      }

    }

  

    {

      ptr rbase_sym = Sstring_to_symbol("racket/base");

      ptr repl_sym = Sstring_to_symbol("read-eval-print-loop");

  

      racket_apply(Scar(racket_dynamic_require(rbase_sym,

                                               repl_sym)),

                   Snil);

    }

  

    return 0;

  }

  

  static ptr to_bytevector(char *s)

  {

    iptr len = strlen(s);

    ptr bv = Smake_bytevector(len, 0);

    memcpy(Sbytevector_data(bv), s, len);

    return bv;

  }

If modules embedded in the executable need to access runtime files (via racket/runtime-path forms), supply the --runtime flag to raco ctool, specifying a directory where the runtime files are to be gathered. The modules in the generated ".c" file will then refer to the files in that directory.