aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile50
-rw-r--r--azure-pipelines.yml61
-rw-r--r--buildcache.go4
-rw-r--r--commands.go10
-rw-r--r--interp/interp_test.go1
-rw-r--r--loader/loader.go6
-rw-r--r--main.go6
-rw-r--r--main_test.go13
-rw-r--r--transform/transform_test.go1
-rw-r--r--util_unix.go20
-rw-r--r--util_windows.go13
11 files changed, 157 insertions, 28 deletions
diff --git a/Makefile b/Makefile
index 3395328ba..7fc00dfd9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,6 @@
# aliases
all: tinygo
-tinygo: build/tinygo
# Default build and source directories, as created by `make llvm-build`.
LLVM_BUILDDIR ?= llvm-build
@@ -33,28 +32,55 @@ else
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
endif
-.PHONY: all tinygo build/tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-avr
+.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-avr
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines debuginfodwarf executionengine instrumentation interpreter ipo irreader linker lto mc mcjit objcarcopts option profiledata scalaropts support target
-UNAME_S := $(shell uname -s)
-ifeq ($(UNAME_S),Linux)
+ifeq ($(OS),Windows_NT)
+ EXE = .exe
START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group
-else ifeq ($(UNAME_S),Darwin)
+
+ # LLVM compiled using MinGW on Windows appears to have problems with threads.
+ # Without this flag, linking results in errors like these:
+ # libLLVMSupport.a(Threading.cpp.obj):Threading.cpp:(.text+0x55): undefined reference to `std::thread::hardware_concurrency()'
+ LLVM_OPTION += -DLLVM_ENABLE_THREADS=OFF
+
+ CGO_LDFLAGS += -static -static-libgcc -static-libstdc++
+ CGO_LDFLAGS_EXTRA += -lversion
+
+ # Build libclang manually because the CMake-based build system on Windows
+ # doesn't allow building libclang as a static library.
+ LIBCLANG_PATH = $(abspath build/libclang-custom.a)
+ LIBCLANG_FILES = $(abspath $(wildcard $(LLVM_BUILDDIR)/tools/clang/tools/libclang/CMakeFiles/libclang.dir/*.cpp.obj))
+
+ # Add the libclang dependency to the tinygo binary target.
+tinygo: $(LIBCLANG_PATH)
+test: $(LIBCLANG_PATH)
+ # Build libclang.
+$(LIBCLANG_PATH): $(LIBCLANG_FILES)
+ @mkdir -p build
+ ar rcs $(LIBCLANG_PATH) $^
+
+else ifeq ($(shell uname -s),Darwin)
MD5SUM = md5
+ LIBCLANG_PATH = $(abspath $(LLVM_BUILDDIR))/lib/libclang.a
+else
+ LIBCLANG_PATH = $(abspath $(LLVM_BUILDDIR))/lib/libclang.a
+ START_GROUP = -Wl,--start-group
+ END_GROUP = -Wl,--end-group
endif
-CLANG_LIBS = $(START_GROUP) $(abspath $(LLVM_BUILDDIR))/lib/libclang.a -lclangAnalysis -lclangARCMigrate -lclangAST -lclangASTMatchers -lclangBasic -lclangCodeGen -lclangCrossTU -lclangDriver -lclangDynamicASTMatchers -lclangEdit -lclangFormat -lclangFrontend -lclangFrontendTool -lclangHandleCXX -lclangHandleLLVM -lclangIndex -lclangLex -lclangParse -lclangRewrite -lclangRewriteFrontend -lclangSema -lclangSerialization -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore -lclangStaticAnalyzerFrontend -lclangTooling -lclangToolingASTDiff -lclangToolingCore -lclangToolingInclusions $(END_GROUP) -lstdc++
+CLANG_LIBS = $(START_GROUP) -lclangAnalysis -lclangARCMigrate -lclangAST -lclangASTMatchers -lclangBasic -lclangCodeGen -lclangCrossTU -lclangDriver -lclangDynamicASTMatchers -lclangEdit -lclangFormat -lclangFrontend -lclangFrontendTool -lclangHandleCXX -lclangHandleLLVM -lclangIndex -lclangLex -lclangParse -lclangRewrite -lclangRewriteFrontend -lclangSema -lclangSerialization -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore -lclangStaticAnalyzerFrontend -lclangTooling -lclangToolingASTDiff -lclangToolingCore -lclangToolingInclusions $(END_GROUP) -lstdc++
LLD_LIBS = $(START_GROUP) -llldCOFF -llldCommon -llldCore -llldDriver -llldELF -llldMachO -llldMinGW -llldReaderWriter -llldWasm -llldYAML $(END_GROUP)
# For static linking.
-ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config)","")
+ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
CGO_CPPFLAGS=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CXXFLAGS=-std=c++11
- CGO_LDFLAGS=-L$(LLVM_BUILDDIR)/lib $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS))
+ CGO_LDFLAGS+=$(LIBCLANG_PATH) -std=c++11 -L$(abspath $(LLVM_BUILDDIR)/lib) $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
endif
@@ -108,9 +134,9 @@ $(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
# Build the Go compiler.
-build/tinygo:
+tinygo:
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
- CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -o build/tinygo -tags byollvm .
+ CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -o build/tinygo$(EXE) -tags byollvm .
test:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -tags byollvm ./interp ./transform .
@@ -198,7 +224,7 @@ endif
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main
-release: build/tinygo gen-device
+release: tinygo gen-device
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@@ -208,7 +234,7 @@ release: build/tinygo gen-device
@mkdir -p build/release/tinygo/pkg/armv7m-none-eabi
@mkdir -p build/release/tinygo/pkg/armv7em-none-eabi
@echo copying source files
- @cp -p build/tinygo build/release/tinygo/bin
+ @cp -p build/tinygo$(EXE) build/release/tinygo/bin
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 000000000..1b5e478c7
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,61 @@
+jobs:
+- job: Build
+ timeoutInMinutes: 180
+ pool:
+ vmImage: 'VS2017-Win2016'
+ steps:
+ - checkout: self
+ - task: CacheBeta@0
+ displayName: Cache LLVM source
+ inputs:
+ key: llvm-source-8-windows-v0
+ path: llvm-project
+ - task: Bash@3
+ displayName: Download LLVM source
+ inputs:
+ targetType: inline
+ script: make llvm-source
+ - task: CacheBeta@0
+ displayName: Cache LLVM build
+ inputs:
+ key: llvm-build-8-windows-v1
+ path: llvm-build
+ - task: Bash@3
+ displayName: Build LLVM
+ inputs:
+ targetType: inline
+ script: |
+ if [ ! -f llvm-build/lib/liblldELF.a ]
+ then
+ choco install ninja
+ make llvm-build
+ fi
+ - task: Bash@3
+ displayName: Install QEMU
+ inputs:
+ targetType: inline
+ script: choco install qemu
+ - task: Bash@3
+ displayName: Test TinyGo
+ inputs:
+ targetType: inline
+ script: |
+ export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
+ make test
+ - task: Bash@3
+ displayName: Build TinyGo release tarball
+ inputs:
+ targetType: inline
+ script: |
+ export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
+ make release -j4
+ - publish: $(System.DefaultWorkingDirectory)/build/release.tar.gz
+ displayName: Publish tarball as artifact
+ artifact: tinygo.windows-amd64.tar.gz
+ - task: Bash@3
+ displayName: Smoke tests
+ inputs:
+ targetType: inline
+ script: |
+ export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
+ make smoketest TINYGO=build/tinygo AVR=0 RISCV=0
diff --git a/buildcache.go b/buildcache.go
index 44b2340af..0628d2889 100644
--- a/buildcache.go
+++ b/buildcache.go
@@ -109,10 +109,10 @@ func moveFile(src, dst string) error {
return err
}
- err = os.Rename(dst+".tmp", dst)
+ err = outf.Close()
if err != nil {
return err
}
- return outf.Close()
+ return os.Rename(dst+".tmp", dst)
}
diff --git a/commands.go b/commands.go
index 0d61c892a..a0fb7aecf 100644
--- a/commands.go
+++ b/commands.go
@@ -24,6 +24,14 @@ func init() {
commands["ld.lld"] = append(commands["ld.lld"], "/usr/local/opt/llvm/bin/ld.lld")
commands["wasm-ld"] = append(commands["wasm-ld"], "/usr/local/opt/llvm/bin/wasm-ld")
}
+ // Add the path for when LLVM was installed with the installer from
+ // llvm.org, which by default doesn't add LLVM to the $PATH environment
+ // variable.
+ if runtime.GOOS == "windows" {
+ commands["clang"] = append(commands["clang"], "clang", "C:\\Program Files\\LLVM\\bin\\clang.exe")
+ commands["ld.lld"] = append(commands["ld.lld"], "lld", "C:\\Program Files\\LLVM\\bin\\lld.exe")
+ commands["wasm-ld"] = append(commands["wasm-ld"], "C:\\Program Files\\LLVM\\bin\\wasm-ld.exe")
+ }
}
func execCommand(cmdNames []string, args ...string) error {
@@ -33,7 +41,7 @@ func execCommand(cmdNames []string, args ...string) error {
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
- if err, ok := err.(*exec.Error); ok && err.Err == exec.ErrNotFound {
+ if err, ok := err.(*exec.Error); ok && (err.Err == exec.ErrNotFound || err.Err.Error() == "file does not exist") {
// this command was not found, try the next
continue
}
diff --git a/interp/interp_test.go b/interp/interp_test.go
index 9e3808540..e83072a65 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -87,6 +87,7 @@ func fuzzyEqualIR(s1, s2 string) bool {
func filterIrrelevantIRLines(lines []string) []string {
var out []string
for _, line := range lines {
+ line = strings.TrimSpace(line) // drop '\r' on Windows
if line == "" || line[0] == ';' {
continue
}
diff --git a/loader/loader.go b/loader/loader.go
index 1cf371565..430e73d96 100644
--- a/loader/loader.go
+++ b/loader/loader.go
@@ -317,9 +317,9 @@ func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
defer rd.Close()
relpath := path
if filepath.IsAbs(path) {
- relpath, err = filepath.Rel(p.Dir, path)
- if err != nil {
- return nil, err
+ rp, err := filepath.Rel(p.Dir, path)
+ if err == nil {
+ relpath = rp
}
}
return parser.ParseFile(p.fset, relpath, rd, mode)
diff --git a/main.go b/main.go
index e0ba19b99..b68a24d2e 100644
--- a/main.go
+++ b/main.go
@@ -552,11 +552,7 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
}
// Make sure the daemon doesn't receive Ctrl-C that is intended for
// GDB (to break the currently executing program).
- // https://stackoverflow.com/a/35435038/559350
- daemon.SysProcAttr = &syscall.SysProcAttr{
- Setpgid: true,
- Pgid: 0,
- }
+ setCommandAsDaemon(daemon)
// Start now, and kill it on exit.
daemon.Start()
defer func() {
diff --git a/main_test.go b/main_test.go
index 9b406d2bb..f0a574bfe 100644
--- a/main_test.go
+++ b/main_test.go
@@ -45,11 +45,13 @@ func TestCompiler(t *testing.T) {
}
defer os.RemoveAll(tmpdir)
- t.Log("running tests on host...")
- for _, path := range matches {
- t.Run(path, func(t *testing.T) {
- runTest(path, tmpdir, "", t)
- })
+ if runtime.GOOS != "windows" {
+ t.Log("running tests on host...")
+ for _, path := range matches {
+ t.Run(path, func(t *testing.T) {
+ runTest(path, tmpdir, "", t)
+ })
+ }
}
if testing.Short() {
@@ -162,6 +164,7 @@ func runTest(path, tmpdir string, target string, t *testing.T) {
// putchar() prints CRLF, convert it to LF.
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
+ expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
// Check whether the command ran successfully.
fail := false
diff --git a/transform/transform_test.go b/transform/transform_test.go
index be242c74a..12240ac5b 100644
--- a/transform/transform_test.go
+++ b/transform/transform_test.go
@@ -70,6 +70,7 @@ func fuzzyEqualIR(s1, s2 string) bool {
func filterIrrelevantIRLines(lines []string) []string {
var out []string
for _, line := range lines {
+ line = strings.TrimSpace(line) // drop '\r' on Windows
if line == "" || line[0] == ';' {
continue
}
diff --git a/util_unix.go b/util_unix.go
new file mode 100644
index 000000000..8be8eb2c0
--- /dev/null
+++ b/util_unix.go
@@ -0,0 +1,20 @@
+// +build !windows
+
+package main
+
+// This file contains utility functions for Unix-like systems (e.g. Linux).
+
+import (
+ "os/exec"
+ "syscall"
+)
+
+// setCommandAsDaemon makes sure this command does not receive signals sent to
+// the parent.
+func setCommandAsDaemon(daemon *exec.Cmd) {
+ // https://stackoverflow.com/a/35435038/559350
+ daemon.SysProcAttr = &syscall.SysProcAttr{
+ Setpgid: true,
+ Pgid: 0,
+ }
+}
diff --git a/util_windows.go b/util_windows.go
new file mode 100644
index 000000000..848c7b1f5
--- /dev/null
+++ b/util_windows.go
@@ -0,0 +1,13 @@
+package main
+
+// This file contains utility functions for Windows.
+
+import (
+ "os/exec"
+)
+
+// setCommandAsDaemon makes sure this command does not receive signals sent to
+// the parent. It is unimplemented on Windows.
+func setCommandAsDaemon(daemon *exec.Cmd) {
+ // Not implemented.
+}