Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,18 @@ ifdef CONFIG_ARM32
MQJS_BUILD_FLAGS=-m32
endif

PROGS=mqjs$(EXE) example$(EXE)
PROGS=mqjs$(EXE) example$(EXE) mqjsc$(EXE)
TEST_PROGS=dtoa_test libm_test

all: $(PROGS)

MQJS_OBJS=mqjs.o readline_tty.o readline.o mquickjs.o dtoa.o libm.o cutils.o
LIB_OBJS=mquickjs.o dtoa.o libm.o cutils.o mqjs_runtime.o mqjs_stdlib_export.o
LIBS=-lm

mqjs$(EXE): $(MQJS_OBJS)
libmquickjs.a: $(LIB_OBJS)
$(AR) rcs $@ $^

mqjs$(EXE): mqjs.o readline_tty.o readline.o libmquickjs.a
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)

mquickjs.o: mquickjs_atom.h
Expand All @@ -98,11 +101,15 @@ mqjs_stdlib.h: mqjs_stdlib
./mqjs_stdlib $(MQJS_BUILD_FLAGS) > $@

mqjs.o: mqjs_stdlib.h
mqjs_stdlib_export.o: mqjs_stdlib.h

# C API example
example.o: example_stdlib.h

example$(EXE): example.o mquickjs.o dtoa.o libm.o cutils.o
example$(EXE): example.o libmquickjs.a
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)

mqjsc$(EXE): mqjsc.o libmquickjs.a
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)

example_stdlib: example_stdlib.host.o mquickjs_build.host.o
Expand All @@ -117,7 +124,7 @@ example_stdlib.h: example_stdlib
%.host.o: %.c
$(HOST_CC) $(HOST_CFLAGS) -c -o $@ $<

test: mqjs example
test: mqjs example mqjsc
./mqjs tests/test_closure.js
./mqjs tests/test_language.js
./mqjs tests/test_loop.js
Expand All @@ -127,6 +134,7 @@ test: mqjs example
# @sha256sum -c test_builtin.sha256
./mqjs -b test_builtin.bin
./example tests/test_rect.js
./tests/test_mqjsc.sh

microbench: mqjs
./mqjs tests/microbench.js
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ Then you can run the compiled bytecode as a normal script:
./mqjs -b mandelbrot.bin
```

## Standalone compiler

`mqjsc` is a compiler that produces a standalone C program binary
executable that embeds the MQuickJS runtime along with the
precompiled bytecode of a script. Usage:

```sh
./mqjsc -o myprog examples/hello.js
./myprog
```

The resulting binary only depends on the standard C library and
libm. It is suitable for deployment on systems without the MQuickJS
engine installed.

The bytecode format depends on the endianness and word length (32 or
64 bit) of the CPU. On a 64 bit CPU, it is possible to use the option
`-m32` to generate 32 bit bytecode that can run on an embedded 32 bit
Expand Down
82 changes: 2 additions & 80 deletions example.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "cutils.h"
#include "mquickjs.h"
#include "mqjs_runtime.h"

#define JS_CLASS_RECTANGLE (JS_CLASS_USER + 0)
#define JS_CLASS_FILLED_RECTANGLE (JS_CLASS_USER + 1)
Expand Down Expand Up @@ -168,87 +169,8 @@ static JSValue js_filled_rectangle_get_color(JSContext *ctx, JSValue *this_val,
return JS_NewInt32(ctx, d->color);
}

static JSValue js_print(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv)
{
int i;
JSValue v;

for(i = 0; i < argc; i++) {
if (i != 0)
putchar(' ');
v = argv[i];
if (JS_IsString(ctx, v)) {
JSCStringBuf buf;
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, v, &buf);
fwrite(str, 1, len, stdout);
} else {
JS_PrintValueF(ctx, argv[i], JS_DUMP_LONG);
}
}
putchar('\n');
return JS_UNDEFINED;
}

#if defined(__linux__) || defined(__APPLE__)
static int64_t get_time_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);
}
#else
static int64_t get_time_ms(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
}
#endif

static JSValue js_date_now(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return JS_NewInt64(ctx, (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000));
}

static JSValue js_performance_now(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv)
{
return JS_NewInt64(ctx, get_time_ms());
}

#include "example_stdlib.h"

static void js_log_func(void *opaque, const void *buf, size_t buf_len)
{
fwrite(buf, 1, buf_len, stdout);
}

static uint8_t *load_file(const char *filename, int *plen)
{
FILE *f;
uint8_t *buf;
int buf_len;

f = fopen(filename, "rb");
if (!f) {
perror(filename);
exit(1);
}
fseek(f, 0, SEEK_END);
buf_len = ftell(f);
fseek(f, 0, SEEK_SET);
buf = malloc(buf_len + 1);
fread(buf, 1, buf_len, f);
buf[buf_len] = '\0';
fclose(f);
if (plen)
*plen = buf_len;
return buf;
}

int main(int argc, const char **argv)
{
size_t mem_size;
Expand All @@ -268,7 +190,7 @@ int main(int argc, const char **argv)
mem_size = 65536;
mem_buf = malloc(mem_size);
ctx = JS_NewContext(mem_buf, mem_size, &js_stdlib);
JS_SetLogFunc(ctx, js_log_func);
mqjs_add_runtime_functions(ctx);

buf = load_file(filename, &buf_len);
val = JS_Eval(ctx, (const char *)buf, buf_len, filename, 0);
Expand Down
6 changes: 6 additions & 0 deletions examples/fib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
var n = scriptArgs.length > 1 ? parseInt(scriptArgs[1]) : 10;
print('fib(' + n + ') = ' + fib(n));
1 change: 1 addition & 0 deletions examples/hello.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print('Hello from a standalone binary!');
Loading