Support GLib version older than 2.64
Allow customizing the WebExtension installation path
Allow extras installation: shells, WebExtension
Kiln is an utility library to ease the development of modules for JavaScriptCore (JSC) with a focus on providing mechanisms for embedders to dynamically load native modules which use the JSC GLib API to provide bindings.
Kiln can be used with the following JSC implementations:
javascriptcoregtk-4.0
library provided by the WebKitGTK port.wpe-webkit-1.0
library provided by the WPE WebKit port.A kiln is a large oven for making bricks. One could think about each module loaded using Kiln as a small brick used to make a complete building.
Kiln uses Meson as its build system. The following options are available:
Option | Description |
---|---|
-Dwebkit_port=gtk |
Use the WebKitGTK JSC library. |
-Dwebkit_port=wpe |
Use WPE WebKit as the JSC library. |
-Djsc_shell=… |
Whether to build the kn-jsc program, a JSC shell that can run JavaScript making use of Kiln plug-in modules, or run as an interactive interpreter. Needs libedit. |
-Dgtk_shell=… |
Whether to build the kn-gtk program, a bare-bones application which embeds a web view and can make use of the Kiln WebExtension. This is only available when building with -Dwebkit_port=gtk and is mostly useful for development. |
-Dweb_extension=… |
Whether to build the Kiln WebExtension. |
-Ddocumentation=… |
Whether to build the Kiln manual using HotDoc. |
Once you have a JSCContext created (either manually, or by WebKit itself as
part of a web view) a KilnLoader
instance can be created to load modules
for that context:
g_autoptr(JSCContext) context = jsc_context_new ();
g_autoptr(KilnLoader) loader = kiln_loader_new (context);
Modules can then be added to the loader in two ways: by instructing the loader to look for loadable shared libraries (plug-in modules) in the file system, or by manually specifying the module properties (name, initialization function, etc.).
Manually specifying modules allows providing bindings for built-in
functionality without the need for building and installing plug-ins. Built-in
modules need to be registered with kiln_loader_add_module()
before trying to
open them. The following defines a module consisting of a single function
to be exposed to JavaScript:
/* Implementation of the native function. */
static void
builtin_print (JSCValue *value)
{
g_autofree char *value_string = jsc_value_to_string (value);
printf ("%s\n", value_string);
}
/* Function that initializes (opens) the module. */
static JSCValue*
open_builtin_print (JSCContext *context, GError **error, void *userdata)
{
/*
* If the module cannot be initialized, return NULL and set the GError.
* The "userdata" parameter will be specified when opening the module.
* The returned value are the module contents.
*/
return jsc_value_new_function (context,
"print",
G_CALLBACK (builtin_print),
NULL, /* userdata */
NULL, /* destroy_notify */
G_TYPE_NONE, /* return type */
1, /* num. of parameters */
JSC_TYPE_VALUE); /* parameter type */
}
With the above in place, the module can be registered with the loader:
g_autoptr(GError) error = NULL;
if (!kiln_loader_add_module (loader,
"print", /* module name */
open_builtin_print, /* module init function */
NULL, /* userdata */
&error))
g_error ("Cannot register module: %s", error->message);
Finally, the module can be “opened” to make the functionality available to the JavaScript world:
if (!kiln_loader_open_module (loader,
"print", /* module name */
&error))
g_error ("Cannot open module: %s", error->message);
This last step takes the value returned from the module initialization function and assigns it to an attribute in the JS global object named after the module:
// Prints "number" using the "builtin_print()" C function.
print(typeof (1 + Number.parseInt("41")));
Plug-ins are loadable shared libraries (on ELF systems, a .so
file) that
contain a public function named kiln_<name>_module_open
, where <name>
is the module name that it implements, and the signature is as follows:
JSCValue* kiln_<name>_module_open (JSCContext*, GError**, void*);
This means that the open_builtin_print()
function from the built-ins
example could be moved into its own file and renamed
as follows to make it into a loadable plug-in:
G_MODULE_EXPORT JSCValue*
kiln_print_module_open (JSCContext *context, GError **error, void *userdata)
This module must be built on its own and installed as lib<name>.so
, in the
case of the example print
module:
$CC -shared -o libprint.so print.c $(pkg-config wpe-webkit-1.0 --libs --cflags)
Once the loadable plug-in module is built, the loader can be taught where to look for loadable modules:
/* Use the current directory for finding plug-in modules. */
kiln_loader_append_path (loader, ".");
/* Open it. This is exactly the same as for built-in modules. */
if (!kiln_loader_open_module (loader, "print", &error))
g_error ("Cannot load module: %s", error->message);
Note that module names must be unique: if a built-in module was already added, a loadable one with the same name will not be used.
Using the kiln_loader_bootstrap
function will register the loader itself in
the JSCContext
as a module, making it possible to change the module search
paths and load further modules from JavaScript. In the native side, the
following will make the JavaScript module available under the kiln
name:
kiln_loader_bootstrap (loader, "kiln", NULL);
kiln_loader_open_module (loader, "kiln", NULL);
Then, on the JavaScript side:
kiln.appendPath("path/to/modules/");
const console = kiln.loadModule("console");
console.log("This was loaded dynamically");
Kiln provides a
Web Extension
which allows to load Kiln modules to be used by content loaded in a
WebKitWebView
. The built libkiln-webkit-*.so
library must be installed
in a location where your application is configured to look
for WebExtensions.
The WebExtension is built when configuring the build with
-Dweb_extension=enabled
.
A simple JSC shell named kn-jsc
is included with Kiln and built when
configuring the build with -Djsc_shell=enabled
. This shell can load
Kiln plug-in modules, run JavaScript scripts in batch mode, and also
be used as an interactive REPL.
The shell expects a console
module to be available in the module
path. The implementation can be found in the modules/
subdirectory and is
built by default. Use kn-jsc --help
for more information on how to specify
module paths, or to disable this “built-in” (in the sense of always
available).
The GTK shell is built when configuring the build with -Dgtk_shell=enabled
and -Dwebkit_port=gtk
. The program is called kn-gtk
, and is most useful
when the WebExtension is also built to make it able to
load Kiln modules. The program consists of bare bones browser window
which opens the URL specified in the command line. Check kn-gtk --help
for more information on how to specify module paths and the location where the
WebExtension is located.
Kiln is distributed under the terms of the MIT license.