Skip to content

Instantly share code, notes, and snippets.

@kaosat-dev
Last active December 20, 2020 06:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kaosat-dev/ea9126a5c9f09b55e2dd6828c698849a to your computer and use it in GitHub Desktop.
Save kaosat-dev/ea9126a5c9f09b55e2dd6828c698849a to your computer and use it in GitHub Desktop.
QuickJS: creating a shared c module and import it as a module in js

QuickJS: creating a shared c module and import it as a module in js

preparing the .c/.h files

  • the first few lines of your .c/.h files are very important !
    • #define countof(x) (sizeof(x) / sizeof((x)[0])) => this one should be copy & pasted, or inclued
    • the JS_INIT_MOULE is also critical as quickjs relies on that ! typos are critical (spent an hour on a typo ...)

compiling

the only (and simplest) example of a makefile I found was https://github.com/khanhas/minnet-quickjs/blob/master/Makefile

  • critical flags (pulled my hair out over them !)
    • -fPIC
    • -shared
    • -DJS_SHARED_LIBRARY * clang & gcc both work with those flags
  • all this got the shared library working for me under Ubutu 20.04

running

if all went well , (and you are in your compilation/ code folder) just run (asuming you have qjs installed at the system level) qjs ./index.js

Voila ! if it went wrong, quickjs will likely complain about not

  • being able to load a shared libary , which is a bit of a misdirection sometimes : even if your .so file does not exist at all you will get the same message !
  • JS_INIT_MODULE not being found : it means something sorta worked, but you either have some typo in the crucial naming parts of your source file, or some less obvious compilation issue (ie, no errors, .so file is generated, but it still does not work)
#include <quickjs/quickjs.h>
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#ifdef JS_SHARED_LIBRARY
#define JS_INIT_MODULE js_init_module
#else
#define JS_INIT_MODULE js_init_module_foo
#endif
static JSValue addNumbers(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
int a, b;
if (JS_ToInt32(ctx, &a, argv[0]))
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &b, argv[1]))
return JS_EXCEPTION;
return JS_NewInt32(ctx, a + b);
}
static const JSCFunctionListEntry js_foo_funcs[] = {
JS_CFUNC_DEF("add", 2, addNumbers),
};
static int js_foo_init(JSContext *ctx, JSModuleDef *m)
{
return JS_SetModuleExportList(ctx, m, js_foo_funcs, countof(js_foo_funcs));
}
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_foo_init);
if (!m)
return NULL;
JS_AddModuleExportList(ctx, m, js_foo_funcs, countof(js_foo_funcs));
return m;
}
import { add } from './foo.so'
console.log('test', add(2, 1))
// run this with qjs <PATH TO>/index.js
CC=clang
FLAGS=-Wall -fPIC -shared -std=gnu17
LIB=-L/usr/lib/quickjs/
DEFINE=-DJS_SHARED_LIBRARY
all:
${CC} ${FLAGS} ${DEFINE} ${LIB} foo.c -o foo.so
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment