diff options
-rw-r--r-- | Makefile | 50 | ||||
-rw-r--r-- | azure-pipelines.yml | 61 | ||||
-rw-r--r-- | buildcache.go | 4 | ||||
-rw-r--r-- | commands.go | 10 | ||||
-rw-r--r-- | interp/interp_test.go | 1 | ||||
-rw-r--r-- | loader/loader.go | 6 | ||||
-rw-r--r-- | main.go | 6 | ||||
-rw-r--r-- | main_test.go | 13 | ||||
-rw-r--r-- | transform/transform_test.go | 1 | ||||
-rw-r--r-- | util_unix.go | 20 | ||||
-rw-r--r-- | util_windows.go | 13 |
11 files changed, 157 insertions, 28 deletions
@@ -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) @@ -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. +} |