From 899a15b725fb2577d2003ecbfd9dac306d651fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Nieper-Wi=C3=9Fkirchen?= <marc@nieper-wisskirchen.de> Date: Mon, 22 Jun 2015 20:37:52 +0200 Subject: [PATCH] Integrate emscripten build process in Makefile Move Emscripten dependencies into separate directory --- .gitignore | 6 ++ Makefile | 16 +++++ js/exported_functions.json | 5 ++ js/index.html | 116 +++++++++++++++++++++++++++++++++++++ js/post.js | 2 + js/pre.js | 6 ++ 6 files changed, 151 insertions(+) create mode 100644 js/exported_functions.json create mode 100644 js/index.html create mode 100644 js/post.js create mode 100644 js/pre.js diff --git a/.gitignore b/.gitignore index 13594214..3009cebd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Object files *.o +*.bc *.ko *.obj *.elf @@ -36,6 +37,7 @@ lib/.*.meta # Generated files chibi-scheme +chibi-scheme-emscripten chibi-scheme.pc include/chibi/install.h lib/chibi/emscripten.c @@ -48,6 +50,7 @@ lib/chibi/system.c lib/chibi/time.c *.tgz *.html +!index.html examples/snow-fort examples/synthcode @@ -58,3 +61,6 @@ tmp /lib/chibi/crypto/crypto.c /chibi-scheme-ulimit /clibs.c + +js/chibi.* + diff --git a/Makefile b/Makefile index dfee9663..7e87009a 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,20 @@ endif all: chibi-scheme$(EXE) all-libs chibi-scheme.pc $(META_FILES) +js: js/chibi.js + +js/chibi.js: chibi-scheme-emscripten chibi-scheme-static.bc js/pre.js js/post.js js/exported_functions.json + emcc -O2 chibi-scheme-static.bc -o $@ -s MODULARIZE=1 -s EXPORT_NAME=\"Chibi\" -s EXPORTED_FUNCTIONS=@js/exported_functions.json `find lib -type f \( -name "*.scm" -or -name "*.sld" \) -printf " --preload-file %p"` --pre-js js/pre.js --post-js js/post.js + +chibi-scheme-static.bc: + emmake $(MAKE) PLATFORM=emscripten CHIBI_DEPENDENCIES= CHIBI=./chibi-scheme-emscripten PREFIX= CFLAGS=-O2 SEXP_USE_DL=0 EXE=.bc SO=.bc CPPFLAGS="-DSEXP_USE_STRICT_TOPLEVEL_BINDINGS=1 -DSEXP_USE_ALIGNED_BYTECODE=1 -DSEXP_USE_STATIC_LIBS=1" clibs.c chibi-scheme-static.bc + +chibi-scheme-emscripten: VERSION + $(MAKE) clean + $(MAKE) chibi-scheme-static PLATFORM=emscripten SEXP_USE_DL=0 + mv chibi-scheme-static$(EXE) chibi-scheme-emscripten + $(MAKE) clean + include/chibi/install.h: Makefile echo '#define sexp_so_extension "'$(SO)'"' > $@ echo '#define sexp_default_module_path "'$(MODDIR):$(BINMODDIR)'"' >> $@ @@ -242,6 +256,8 @@ clean: clean-libs cleaner: clean -$(RM) chibi-scheme$(EXE) chibi-scheme-static$(EXE) chibi-scheme-ulimit$(EXE) \ libchibi-scheme$(SO)* *.a *.pc include/chibi/install.h lib/.*.meta \ + chibi-scheme-emscripten \ + js/chibi.* \ $(shell $(FIND) lib -name \*.o) dist-clean: dist-clean-libs cleaner diff --git a/js/exported_functions.json b/js/exported_functions.json new file mode 100644 index 00000000..da719553 --- /dev/null +++ b/js/exported_functions.json @@ -0,0 +1,5 @@ +[ + '_main', + '_sexp_resume' +] + diff --git a/js/index.html b/js/index.html new file mode 100644 index 00000000..be273b9c --- /dev/null +++ b/js/index.html @@ -0,0 +1,116 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Chibi-Scheme</title> + <style> + body { + font-family: sans-serif; + height: 100vh; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + } + main { + flex: 1; + display: flex; + flex-direction: column; + } + #program { + flex: 1 1 0; + padding: 0.5em; + } + #start { + font-size: inherit; + padding: 0.5em; + } + #output { + font-family: monospace; + padding: 0.5em; + white-space: pre; + background-color: #000; + color: #fff; + overflow: auto; + flex: 1 1 0; + } + </style> + </head> + <body> + <main> + <textarea id="program" spellcheck="false">; +; This is Chibi-Scheme compiled with Emscripten to run in the browser. +; + +(import (scheme base)) +(write-string "Hello, world!\n") + +; +; You can also run arbitrary JavaScript code from scheme and yield control back and forth between Scheme and the browser +; + +(import (chibi emscripten)) ; exports: eval-script!, integer-eval-script, string-eval-script, wait-on-event! + +(write-string (number->string (integer-eval-script "6 * 7"))) +(newline) + +(eval-script! "window.addEventListener('click', function () { + Module['resume'](); // give control back to the Scheme process +})") + +(let loop () + (wait-on-event!) ; yields control back to the browser + (write-string "You have clicked me!\n") + (loop)) + +(write-string "Control never reaches this point\n") +</textarea> + <button type="button" id="start" disabled>Start Program</button> + <div id="output"></div> + </main> + <script src="chibi.js"></script> + <script> + function start(program, args, onOutput, onError) { + var firstError = true; + Chibi({ + print: onOutput, + printErr: function (text) { + if (firstError) { + firstError = false; + return; + } + if (onError !== undefined) { + onError(text); + } else { + onOutput(text); + } + }, + program: program, + arguments: args + }); + } + </script> + <script> + (function () { + var programField = document.querySelector('#program'); + var startButton = document.querySelector('#start'); + var program = sessionStorage.getItem('program'); + if (program) { + programField.value = program; + } + programField.addEventListener('input', function() { + sessionStorage.setItem('program', programField.value); + }); + startButton.addEventListener('click', function() { + var program = programField.value; + startButton.disabled = true; + start(program, [], + function(text) { + output.textContent = output.textContent + text + '\n' + }); + }); + startButton.disabled = false; + })(); + </script> + </body> +</html> diff --git a/js/post.js b/js/post.js new file mode 100644 index 00000000..40e37566 --- /dev/null +++ b/js/post.js @@ -0,0 +1,2 @@ +Module['resume'] = Module.cwrap('sexp_resume', 'void', []); + diff --git a/js/pre.js b/js/pre.js new file mode 100644 index 00000000..8bb97bf5 --- /dev/null +++ b/js/pre.js @@ -0,0 +1,6 @@ +Module['preRun'].push(function () { + FS.writeFile('program.scm', Module['program']); +}); +Module['arguments'] = Module['arguments'] || []; +Module['arguments'].unshift('program.scm'); +