Janet 1.5.1-5171dfd Documentation
(Other Versions: 1.5.0 1.4.0 1.3.1)

The Janet C API

One of the fundamental design goals of Janet is to extend it via the C programming language, as well as embed the interpreter in a larger program. To this end, Janet exposes most of it's low level functionality in well defined C API. Unlike Janet, the Janet C API is not safe — it's possible to write programs in C that will crash, use memory after freeing it, or simply cause undefined behavior. However, using the C API will let you use high performance libraries on almost any system and access native functionality that is not possible in pure Janet.

Janet's C API assumes that you will have one Janet interpreter per OS thread (if the system you are on has threads). The means that Janet must have some global, thread local state. This is a problem for some host languages, like Go, that expect all code to be fully re-entrant on any thread. This design choice, however, makes the Janet APIs more pleasant to use in languages like C and C++, as there is no need to pass around a context object to all api functions.

What defines the C API?

The C API is defined by the header janet.h, which should be included by programs to both embed Janet in a larger program, or to write a Janet module.

Writing a Module

The easiest way to get started with the Janet C API is to write a Janet native module. A native module is native code that can be loaded dynamically at runtime in the interpreter.

A basic skeleton for a native module in C is below.

#include <janet.h>

static Janet myfun(int32_t argc, const Janet *argv) {
    janet_fixarity(argc, 0);
    printf("hello from a module!\n");
    return janet_wrap_nil();
}

static const JanetReg cfuns[] = {
    {"myfun", myfun, "(mymod/myfun)\n\nPrints a hello message."},
    {NULL, NULL, NULL}
};

JANET_MODULE_ENTRY(JanetTable *env) {
    janet_cfuns(env, "mymod", cfuns);
}

This module is a very simple module that exposes one native function called myfun. The module is called mymod, although when importing the module, the user can rename it to whatever he or she likes.

Compiling the Module

Once you have written you native code a file mymod.c, you will need to compile it with your system's C compiler. The easiest way to do this is to use jpm and write a project.janet file. jpm will handle all of the linking and flags for you so that you can write portable modules. Since project.janet is just a Janet script, you can detect what platform you are running on and do conditional compilation there if needed.

Inside project.janet:

(declare-project :name "mymod")
(declare-native :name "mymod" :source @["mymod.c"])

Once you have project.janet written, run jpm build to build the module. If all goes well, cook should have built a file build/mymod.so. In your repl, you can now import your module and use it.

(import build/mymod :as mymod)
(mymod/myfun) # Prints the hello message

Congratulations, you have a native module.