Fork of the fantastic QuickJS engine by Fabrice Bellard, with the following changes:
stdandosbuiltin modules are now namespaced under "quickjs:". In other words, you have to import them as "quickjs:std" and "quickjs:os".- APIs in
stdandosno longer return errno anywhere; instead, Error objects are thrown.errnois available as a property on the thrown Error objects. - In places where APIs in
stdoroswould return null on failure, now an error will be thrown instead. - Error messages from
stdandosinclude information in the message such as the path to the file that couldn't be loaded. This info is also available as properties on the Error object. .jsextensions can now be omitted from import specifiers; they're optional.- If your import specifier points to a folder, it will attempt to load
index.jsfrom that folder.
- A TypeScript
.d.tsfile is provided for all APIs (globals as well as stuff fromstd/os). - Synchronous import functions added (
require, or the more flexiblestd.importModule).- Both of these functions provide the same module record object you would get via dynamic (async) import.
- The
requirefunction is not fully CommonJS-compliant; for instance,require.mainis not present.
- Module resolution functions added (
require.resolve, orstd.resolveModule). - A builtin global function
inspectis added, which pretty-prints any JS value as a string. - A builtin global object
Moduleis added.instanceof Modulecan be used to identify module namespace objects.- You can specify additional implicit import specifier extensions by adding to the
Module.searchExtensionsarray. - You can transform any file prior to evaluating it as a module by adding a function to the
Module.compilersobject. Useful for compile-to-ts languages like TypeScript, Coffeescript, etc. - You can define custom builtin modules using the
Module.definefunction. - You can override module name normalization (aka module resolution) by replacing the
Module.resolvefunction.- Note that you must handle
Module.searchExtensionsyourself in your replacement implementation.
- Note that you must handle
- You can override the method used to load modules by replacing the
Module.readfunction.- Note that you must handle
Module.compilersyourself in your replacement implementation.
- Note that you must handle
os.accessfunction added (wrapper for libcaccess).FILE.prototype.syncmethod added (wrapper forfsync).std.isFILEfunction added (returns whether the provided object is aFILE(viajs_std_file_class_id)).os.{WUNTRACED,WEXITSTATUS,WTERMSIG,WSTOPSIG,WIFEXITED,WIFSIGNALED,WIFSTOPPED,WIFCONTINUED}added, for working withos.waitpid.setTimeoutandclearTimeoutare now available as globals.setIntervalandclearIntervalare now available as globals.String.cookedis now available (no-op template tag, like the proposed String.cooked).String.dedentis now available (template tag function, like the proposed String.dedent).
Object.toPrimitiveis now available (static method that invokes ToPrimitive on the given value, using the optionally-provided hint).Symbol.typeofValuecan be used to override the result of using thetypeofoperator on an object. However, you can only use it to return a different one of the builtin valuestypeofwould normally return:"object","boolean","number", etc.- Additional functions are exposed that allow importing modules synchronously or asynchronously:
JS_DynamicImportAsyncJS_DynamicImportSyncJS_DynamicImportSync2(additional arg for specifying basename that the import specifier is relative to)
- Additional error-related functions added:
JS_ThrowErrorJS_AddPropertyToException
- Additional utility functions added:
JS_FreezeObjectValue(performs Object.freeze)
- ModuleDefs now have an optional "user_data" property (pointer to void) which can be accessed during module initialization (via
JS_GetModuleUserDataandJS_SetModuleUserData)
Appending some JS code to the end of this binary changes it into a binary that executes that JS code:
$ cp qjsbootstrap my-program
$ echo 'console.log("hello!")' >> my-program
$ ./my-program
hello!You can use this to create distributable binaries that run JS code without needing to use qjsc or a C compiler. Instructions here.
Note: On FreeBSD,
qjsbootstraprequires procfs. You can mount it withmount -t procfs proc /proc. I started some work to use libprocstat instead, but haven't completed it yet.
A Module that exposes QuickJS's value <-> bytecode (de)serialization APIs to JavaScript code. Generated bytecode can be combined with qjsbootstrap-bytecode in the same way that source code strings can be combined with qjsbootstrap.
Helper structs, functions, and macros that make it easier to work with QuickJS objects in C code.
- Stuff is reorganized into separate folders under
src. - Ninja is used instead of make. Ninja build config is generated via
.ninja.jsfiles which get loaded into @suchipi/shinobi. - macOS binaries are now cross-compiled from Linux
- we now compile ARM macOS binaries as well
- These should work on both M1/M2/etc macbooks as well as on jailbroken iPhones/iPads
- we compile aarch64 (arm 64) binaries for linux, too
- these are statically linked, so should work on a raspi/etc, in theory. maybe android, too
- Line endings have been made consistent and trailing whitespace has been removed
- FreeBSD support added (but there's no cross-compilation set up, so you'll have to compile it yourself from a FreeBSD machine).
- I'm in the process of converting the tests to a new format (which gets run by jest). But I haven't touched most of the old tests yet.
There are also probably some other miscellaneous changes I forgot to write down in the README.
The repo has stuff set up to compile quickjs binaries for Linux, macOS, iOS, FreeBSD, or Windows.
QuickJS itself has no external dependencies outside this repo except pthreads, and all of the code is C99. As such, it shouldn't be too difficult to get it compiling on other Unix-like OSes. OS-specific configuration is done by way of config files found in the meta/ninja/env folder.
Linux, macOS, iOS, and Windows binaries can be compiled using Docker. Or, you can compile binaries for just your own unix system, without using Docker.
If you're not gonna use Docker, you'll need to install Ninja and Node.js in order to compile. I use Ninja 1.10.1 and Node.js 18.12.1, but it should work with most versions of both of those.
To compile binaries for Linux, macOS, iOS, and Windows (using Docker):
- Make sure you have docker installed.
- Clone the repo and cd to its folder
- Run
meta/docker/build-all.sh - Build artifacts will be placed in the
buildfolder, organized by OS.
Or, to compile binaries for just your own unix system:
- Make sure you have both Ninja and Node.js installed. I use Ninja 1.10.1 and Node.js 18.12.1, but it should work with most versions of both of those.
- Clone the repo and cd to its folder
- Run
meta/build.sh - Build artifacts will be placed in the
buildfolder. You're probably most interested in stuff in thebuild/binandbuild/libfolders.
If you are targeting an unsupported OS or would like to use a different compiler, set the environment variables HOST and TARGET both to "other", and then set the environment variables CC, AR, CFLAGS, and LDFLAGS as you see fit. There are some other variables you can set as well; see meta/ninja/envs/target/other.ninja.js and meta/ninja/envs/host/other.ninja.js for a list.
The old tests for std and os aren't working right now; I really haven't touched them yet, so they're still expecting the old function signatures (returning errno, etc).