diff --git a/.travis.yml b/.travis.yml index 4b940333..d6ed9577 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - echo "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-7 main" | sudo tee -a /etc/apt/sources.list - echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list - sudo apt-get update -qq - - sudo apt-get install llvm-7-dev clang-7 gcc-arm-none-eabi qemu-system-arm --allow-unauthenticated -y + - sudo apt-get install llvm-7-dev clang-7 lld-7 gcc-arm-none-eabi qemu-system-arm --allow-unauthenticated -y - sudo ln -s /usr/bin/clang-7 /usr/local/bin/cc # work around missing -no-pie in old GCC version install: @@ -27,3 +27,4 @@ script: - tinygo build -o test.nrf.elf -target=nrf52840-mdk examples/blinky1 - tinygo build -o blinky1.stm32.elf -target=bluepill examples/blinky1 - tinygo build -o blinky1.avr.o -target=arduino examples/blinky1 # TODO: avr-as/avr-gcc doesn't work + - tinygo build -o test.wasm.wasm -target=wasm examples/test diff --git a/Dockerfile b/Dockerfile index 61904a3a..09486d66 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,6 @@ COPY --from=0 /go/src/github.com/aykevl/tinygo/targets /go/src/github.com/aykevl RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \ echo "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-7 main" >> /etc/apt/sources.list && \ apt-get update && \ - apt-get install -y libllvm7 + apt-get install -y libllvm7 lld-7 ENTRYPOINT ["/go/bin/tinygo"] diff --git a/docs/installation.rst b/docs/installation.rst index 1cf8dc7b..7a3670ad 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -44,6 +44,13 @@ needs the following tools: ``avr-gcc``. * ``avrdude`` for flashing to an Arduino. +WebAssembly +~~~~~~~~~~~ + +The WebAssembly backend only needs a special linker from the LLVM project: + + * LLVM linker (``ld.lld-7``) for linking WebAssembly files together. + Installation ------------ diff --git a/main.go b/main.go index 4aa4731d..e53ec606 100644 --- a/main.go +++ b/main.go @@ -91,13 +91,15 @@ func Compile(pkgName, outpath, opt string, spec *TargetSpec, printIR, dumpSSA, d } // Generate output. - if strings.HasSuffix(outpath, ".o") { + outext := filepath.Ext(outpath) + switch outext { + case ".o": return c.EmitObject(outpath) - } else if strings.HasSuffix(outpath, ".bc") { + case ".bc": return c.EmitBitcode(outpath) - } else if strings.HasSuffix(outpath, ".ll") { + case ".ll": return c.EmitText(outpath) - } else { + default: // Act as a compiler driver. // Create a temporary directory for intermediary files. @@ -160,14 +162,13 @@ func Compile(pkgName, outpath, opt string, spec *TargetSpec, printIR, dumpSSA, d } } - ext := filepath.Ext(outpath) - if ext == ".hex" || ext == ".bin" { + if outext == ".hex" || outext == ".bin" { // Get an Intel .hex file or .bin file from the .elf file. - tmppath = filepath.Join(dir, "main"+ext) + tmppath = filepath.Join(dir, "main"+outext) format := map[string]string{ ".hex": "ihex", ".bin": "binary", - }[ext] + }[outext] cmd := exec.Command(spec.Objcopy, "-O", format, executable, tmppath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -386,7 +387,7 @@ func main() { opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z") printIR := flag.Bool("printir", false, "print LLVM IR") dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA") - target := flag.String("target", llvm.DefaultTargetTriple(), "LLVM target") + target := flag.String("target", "", "LLVM target") printSize := flag.String("size", "", "print sizes (none, short, full)") nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation") ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug") @@ -415,7 +416,11 @@ func main() { usage() os.Exit(1) } - err := Build(flag.Arg(0), *outpath, *target, *opt, *printIR, *dumpSSA, !*nodebug, *printSize) + target := *target + if target == "" && filepath.Ext(*outpath) == ".wasm" { + target = "wasm" + } + err := Build(flag.Arg(0), *outpath, target, *opt, *printIR, *dumpSSA, !*nodebug, *printSize) if err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1) @@ -443,7 +448,7 @@ func main() { os.Exit(1) } var err error - if *target == llvm.DefaultTargetTriple() { + if *target == "" { err = Run(flag.Arg(0)) } else { err = Emulate(flag.Arg(0), *target, *opt) diff --git a/src/examples/wasm/wasm.go b/src/examples/wasm/wasm.go new file mode 100644 index 00000000..846fa749 --- /dev/null +++ b/src/examples/wasm/wasm.go @@ -0,0 +1,9 @@ +package main + +func main() { +} + +//go:export add +func add(a, b int) int { + return a + b +} diff --git a/src/examples/wasm/wasm.html b/src/examples/wasm/wasm.html new file mode 100644 index 00000000..d2e1bc15 --- /dev/null +++ b/src/examples/wasm/wasm.html @@ -0,0 +1,15 @@ + + + +
+ +Add two numbers, using WebAssembly:
+ + = + + diff --git a/src/examples/wasm/wasm.js b/src/examples/wasm/wasm.js new file mode 100644 index 00000000..6b0aef7e --- /dev/null +++ b/src/examples/wasm/wasm.js @@ -0,0 +1,55 @@ +'use strict'; + +const WASM_URL = '../../../wasm.wasm'; + +var wasm; +var logLine = []; +var memory8; + +var importObject = { + env: { + io_get_stdout: function() { + return 1; + }, + resource_write: function(fd, ptr, len) { + if (fd == 1) { + for (let i=0; i