From: Jean Privat Date: Tue, 17 Jun 2014 02:17:34 +0000 (-0400) Subject: Merge: Compilation to JavaScript using the Emscripten SDK X-Git-Tag: v0.6.6~28 X-Git-Url: http://nitlanguage.org?hp=7d82bab6b7578952282491566c7e583a5cbeaa24 Merge: Compilation to JavaScript using the Emscripten SDK Published for review but still needs some doc and examples. Works with most small examples but not yet with the naive_interpreter (but it's not clear why). Usage: apt-get emscripten nitg -m emscripten examples/hello_world.nit nodejs hello_wold.js Pull-Request: #506 Reviewed-by: Jean Privat Reviewed-by: Lucas Bajolet Reviewed-by: Alexandre Terrasa --- diff --git a/examples/emscripten/README.md b/examples/emscripten/README.md new file mode 100644 index 0000000..0d84b15 --- /dev/null +++ b/examples/emscripten/README.md @@ -0,0 +1,9 @@ +# Hello world + +Minimal example using the standard Nit hello world program. The Nit code will be evaluated and executed once as soon as it is loaded. Standard output is redirected to the `console` element. + +# Fibonacci + +The Nit program is executed only when an input is supplied. The input is passed as the main arguments. + +This is not ideal, the whole Nit program is executed at each call. diff --git a/examples/emscripten/fibonacci/Makefile b/examples/emscripten/fibonacci/Makefile new file mode 100644 index 0000000..4ec01ea --- /dev/null +++ b/examples/emscripten/fibonacci/Makefile @@ -0,0 +1,2 @@ +emscripten: + ../../../bin/nitg -o www/fibonacci.js ../../fibonacci.nit -m emscripten diff --git a/examples/emscripten/fibonacci/www/index.html b/examples/emscripten/fibonacci/www/index.html new file mode 100644 index 0000000..e0195f6 --- /dev/null +++ b/examples/emscripten/fibonacci/www/index.html @@ -0,0 +1,73 @@ + + + + + Fibonacci + + + + + + + +
+

Fibonacci calculator

+ Nit source
+ HTML source + +

Status

+

Loading...

+ +

Program Input

+ + +

Program Output

+ + + +
+ + + diff --git a/examples/emscripten/hello_world/Makefile b/examples/emscripten/hello_world/Makefile new file mode 100644 index 0000000..5fea224 --- /dev/null +++ b/examples/emscripten/hello_world/Makefile @@ -0,0 +1,2 @@ +emscripten: + ../../../bin/nitg -o www/hello_world.js ../../hello_world.nit -m emscripten diff --git a/examples/emscripten/hello_world/www/index.html b/examples/emscripten/hello_world/www/index.html new file mode 100644 index 0000000..0820561 --- /dev/null +++ b/examples/emscripten/hello_world/www/index.html @@ -0,0 +1,48 @@ + + + + + + + + + + +

Status

+

Loading...

+ +

Program output

+ + + + + + diff --git a/lib/emscripten.nit b/lib/emscripten.nit new file mode 100644 index 0000000..7fc5e76 --- /dev/null +++ b/lib/emscripten.nit @@ -0,0 +1,30 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Alexis Laferrière +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module emscripten is platform + +`{ + #include +`} + +redef class String + fun run_js do run_js_native(self.escape_to_js.to_cstring) + private fun run_js_native(script: NativeString) `{ emscripten_run_script(script); `} + + fun escape_to_js: String do return self.replace('\n', "\\n") + + fun alert do "alert('{self.escape_to_js}')".run_js +end diff --git a/lib/standard/stream.nit b/lib/standard/stream.nit index 504396a..79e601f 100644 --- a/lib/standard/stream.nit +++ b/lib/standard/stream.nit @@ -20,6 +20,7 @@ in "C" `{ #include #include #include + #include `} # Abstract stream class diff --git a/src/abstract_compiler.nit b/src/abstract_compiler.nit index 0093e60..c2785ed 100644 --- a/src/abstract_compiler.nit +++ b/src/abstract_compiler.nit @@ -202,8 +202,12 @@ class MakefileToolchain do if self.toolcontext.opt_stacktrace.value == "nitstack" then compiler.build_c_to_nit_bindings + var platform = compiler.mainmodule.target_platform + var cc_opt_with_libgc = "-DWITH_LIBGC" + if platform != null and not platform.supports_libgc then cc_opt_with_libgc = "" + # Add gc_choser.h to aditionnal bodies - var gc_chooser = new ExternCFile("gc_chooser.c", "-DWITH_LIBGC") + var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc) compiler.extern_bodies.add(gc_chooser) compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.c" compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.h" @@ -288,18 +292,19 @@ class MakefileToolchain self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2) end + fun makefile_name(mainmodule: MModule): String do return "{mainmodule.name}.mk" + + fun default_outname(mainmodule: MModule): String do return mainmodule.name + fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do var mainmodule = compiler.mainmodule - var outname = self.toolcontext.opt_output.value - if outname == null then - outname = "{mainmodule.name}" - end + var outname = self.toolcontext.opt_output.value or else default_outname(mainmodule) var orig_dir=".." # FIXME only works if `compile_dir` is a subdirectory of cwd var outpath = orig_dir.join_path(outname).simplify_path - var makename = "{mainmodule.name}.mk" + var makename = makefile_name(mainmodule) var makepath = "{compile_dir}/{makename}" var makefile = new OFStream.open(makepath) @@ -367,7 +372,7 @@ class MakefileToolchain fun compile_c_code(compiler: AbstractCompiler, compile_dir: String) do - var makename = "{compiler.mainmodule.name}.mk" # FIXME duplicated from write_makefile + var makename = makefile_name(compiler.mainmodule) var makeflags = self.toolcontext.opt_make_flags.value if makeflags == null then makeflags = "" diff --git a/src/emscripten_platform.nit b/src/emscripten_platform.nit new file mode 100644 index 0000000..4c53b36 --- /dev/null +++ b/src/emscripten_platform.nit @@ -0,0 +1,56 @@ +# This file is part of NIT ( http://www.nitlanguage.org ) +# +# Copyright 2014 Alexis Laferrière +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Compile to JavaScript using the Emscripten SDK +module emscripten_platform + +import platform +import abstract_compiler + +redef class ToolContext + redef fun platform_from_name(name) + do + if name == "emscripten" then return new EmscriptenPlatform + return super + end +end + +class EmscriptenPlatform + super Platform + + redef fun supports_libunwind do return false + redef fun supports_libgc do return false + redef fun toolchain(toolcontext) do return new EnscriptenToolchain(toolcontext) +end + +class EnscriptenToolchain + super MakefileToolchain + + redef fun makefile_name(mainmodule) do return "{mainmodule.name}.js.mk" + + redef fun default_outname(mainmodule) do return "{super}.js" + + redef fun write_makefile(compiler, compile_dir, cfiles) + do + super + + var emcc_make_flags = "CC=emcc CFLAGS='-g -Wno-unused-value -Wno-switch -Qunused-arguments'" + + var make_flags = self.toolcontext.opt_make_flags.value or else "" + make_flags += emcc_make_flags + self.toolcontext.opt_make_flags.value = make_flags + end +end diff --git a/src/nitg.nit b/src/nitg.nit index 0714632..66cd891 100644 --- a/src/nitg.nit +++ b/src/nitg.nit @@ -27,6 +27,7 @@ import separate_compiler import android_platform import compiler_ffi import pnacl_platform +import emscripten_platform redef class ToolContext redef fun process_options(args) diff --git a/src/platform.nit b/src/platform.nit index 17257f5..3c5367f 100644 --- a/src/platform.nit +++ b/src/platform.nit @@ -113,6 +113,8 @@ end abstract class Platform fun supports_libunwind: Bool do return true + fun supports_libgc: Bool do return true + # Does this platform declare its own main function? If so, we won't generate one in Nit. fun no_main: Bool do return false end diff --git a/tests/niti.skip b/tests/niti.skip index f9489e3..7c2762c 100644 --- a/tests/niti.skip +++ b/tests/niti.skip @@ -19,3 +19,4 @@ test_android_platform android nitcc_parser_gen mnit +emscripten diff --git a/tests/sav/emscripten.res b/tests/sav/emscripten.res new file mode 100644 index 0000000..174d681 --- /dev/null +++ b/tests/sav/emscripten.res @@ -0,0 +1 @@ +Not executable (platform?)