all: add macOS support
Этот коммит содержится в:
родитель
2d5bc836f5
коммит
0b212cf2f6
11 изменённых файлов: 119 добавлений и 52 удалений
17
.travis.yml
17
.travis.yml
|
@ -4,6 +4,9 @@ matrix:
|
||||||
include:
|
include:
|
||||||
- dist: xenial
|
- dist: xenial
|
||||||
go: "1.11"
|
go: "1.11"
|
||||||
|
- os: osx
|
||||||
|
go: "1.11"
|
||||||
|
env: PATH="/usr/local/opt/llvm/bin:$PATH"
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
|
@ -24,8 +27,16 @@ addons:
|
||||||
- qemu-user
|
- qemu-user
|
||||||
- gcc-avr
|
- gcc-avr
|
||||||
- avr-libc
|
- avr-libc
|
||||||
|
homebrew:
|
||||||
|
update: true
|
||||||
|
taps: ArmMbed/homebrew-formulae
|
||||||
|
packages:
|
||||||
|
- llvm@7
|
||||||
|
- qemu
|
||||||
|
- arm-none-eabi-gcc
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then mkdir -p /Users/travis/gopath/bin; fi
|
||||||
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||||
- dep ensure --vendor-only
|
- dep ensure --vendor-only
|
||||||
|
|
||||||
|
@ -35,14 +46,14 @@ script:
|
||||||
- make gen-device
|
- make gen-device
|
||||||
- tinygo build -size short -o blinky1.nrf.elf -target=pca10040 examples/blinky1
|
- tinygo build -size short -o blinky1.nrf.elf -target=pca10040 examples/blinky1
|
||||||
- tinygo build -size short -o blinky2.nrf.elf -target=pca10040 examples/blinky2
|
- tinygo build -size short -o blinky2.nrf.elf -target=pca10040 examples/blinky2
|
||||||
- tinygo build -size short -o blinky2 examples/blinky2
|
- tinygo build -o blinky2 examples/blinky2 # TODO: re-enable -size flag with MachO support
|
||||||
- tinygo build -size short -o test.nrf.elf -target=pca10040 examples/test
|
- tinygo build -size short -o test.nrf.elf -target=pca10040 examples/test
|
||||||
- tinygo build -size short -o blinky1.nrf51.elf -target=microbit examples/echo
|
- tinygo build -size short -o blinky1.nrf51.elf -target=microbit examples/echo
|
||||||
- tinygo build -size short -o test.nrf.elf -target=nrf52840-mdk examples/blinky1
|
- tinygo build -size short -o test.nrf.elf -target=nrf52840-mdk examples/blinky1
|
||||||
- tinygo build -size short -o blinky1.nrf51d.elf -target=pca10031 examples/blinky1
|
- tinygo build -size short -o blinky1.nrf51d.elf -target=pca10031 examples/blinky1
|
||||||
- tinygo build -size short -o blinky1.stm32.elf -target=bluepill examples/blinky1
|
- tinygo build -size short -o blinky1.stm32.elf -target=bluepill examples/blinky1
|
||||||
- tinygo build -size short -o blinky1.avr.elf -target=arduino examples/blinky1
|
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then tinygo build -size short -o blinky1.avr.elf -target=arduino examples/blinky1; fi
|
||||||
- tinygo build -size short -o blinky1.avr.elf -target=digispark examples/blinky1
|
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then tinygo build -size short -o blinky1.avr.elf -target=digispark examples/blinky1; fi
|
||||||
- tinygo build -size short -o blinky1.reel.elf -target=reelboard examples/blinky1
|
- tinygo build -size short -o blinky1.reel.elf -target=reelboard examples/blinky1
|
||||||
- tinygo build -size short -o blinky2.reel.elf -target=reelboard examples/blinky2
|
- tinygo build -size short -o blinky2.reel.elf -target=reelboard examples/blinky2
|
||||||
- tinygo build -size short -o blinky1.pca10056.elf -target=pca10056 examples/blinky1
|
- tinygo build -size short -o blinky1.pca10056.elf -target=pca10056 examples/blinky1
|
||||||
|
|
6
Gopkg.lock
сгенерированный
6
Gopkg.lock
сгенерированный
|
@ -11,15 +11,15 @@
|
||||||
"go/types/typeutil",
|
"go/types/typeutil",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "40960b6deb8ecdb8bcde6a8f44722731939b8ddc"
|
revision = "3744606dbb67b99c60d3f11cb10bd3f9e6dad472"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:3611159788efdd4e0cfae18b6ebcccbad25a2815968b0e4323b42647d201031a"
|
digest = "1:a6a25fd8906c74978f1ed811bc9fd3422da8093be863b458874b02a782b6ae3e"
|
||||||
name = "tinygo.org/x/go-llvm"
|
name = "tinygo.org/x/go-llvm"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "f420620d1a0f54417a5712260153fe861780d030"
|
revision = "d5f730401f5069618b275a5241c6417eb0c38a65"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
|
|
@ -1353,7 +1353,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fn.RelString(nil) {
|
switch fn.RelString(nil) {
|
||||||
case "syscall.Syscall", "syscall.Syscall6":
|
case "syscall.Syscall", "syscall.Syscall6", "syscall.Syscall9":
|
||||||
return c.emitSyscall(frame, instr)
|
return c.emitSyscall(frame, instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,20 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||||
num, _ := constant.Uint64Val(call.Args[0].(*ssa.Const).Value)
|
num, _ := constant.Uint64Val(call.Args[0].(*ssa.Const).Value)
|
||||||
var syscallResult llvm.Value
|
var syscallResult llvm.Value
|
||||||
switch {
|
switch {
|
||||||
case c.GOARCH == "amd64" && c.GOOS == "linux":
|
case c.GOARCH == "amd64":
|
||||||
|
if c.GOOS == "darwin" {
|
||||||
|
// Darwin adds this magic number to system call numbers:
|
||||||
|
//
|
||||||
|
// > Syscall classes for 64-bit system call entry.
|
||||||
|
// > For 64-bit users, the 32-bit syscall number is partitioned
|
||||||
|
// > with the high-order bits representing the class and low-order
|
||||||
|
// > bits being the syscall number within that class.
|
||||||
|
// > The high-order 32-bits of the 64-bit syscall number are unused.
|
||||||
|
// > All system classes enter the kernel via the syscall instruction.
|
||||||
|
//
|
||||||
|
// Source: https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/syscall_sw.h
|
||||||
|
num += 0x2000000
|
||||||
|
}
|
||||||
// Sources:
|
// Sources:
|
||||||
// https://stackoverflow.com/a/2538212
|
// https://stackoverflow.com/a/2538212
|
||||||
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#syscall
|
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#syscall
|
||||||
|
@ -34,6 +47,9 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||||
"{r10}",
|
"{r10}",
|
||||||
"{r8}",
|
"{r8}",
|
||||||
"{r9}",
|
"{r9}",
|
||||||
|
"{r11}",
|
||||||
|
"{r12}",
|
||||||
|
"{r13}",
|
||||||
}[i]
|
}[i]
|
||||||
llvmValue, err := c.parseExpr(frame, arg)
|
llvmValue, err := c.parseExpr(frame, arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -119,21 +135,42 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS+"/"+c.GOARCH)
|
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS+"/"+c.GOARCH)
|
||||||
}
|
}
|
||||||
// Return values: r0, r1, err uintptr
|
switch c.GOOS {
|
||||||
// Pseudocode:
|
case "linux":
|
||||||
// var err uintptr
|
// Return values: r0, r1 uintptr, err Errno
|
||||||
// if syscallResult < 0 && syscallResult > -4096 {
|
// Pseudocode:
|
||||||
// err = -syscallResult
|
// var err uintptr
|
||||||
// }
|
// if syscallResult < 0 && syscallResult > -4096 {
|
||||||
// return syscallResult, 0, err
|
// err = -syscallResult
|
||||||
zero := llvm.ConstInt(c.uintptrType, 0, false)
|
// }
|
||||||
inrange1 := c.builder.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
|
// return syscallResult, 0, err
|
||||||
inrange2 := c.builder.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(c.uintptrType, 0xfffffffffffff000, true), "") // -4096
|
zero := llvm.ConstInt(c.uintptrType, 0, false)
|
||||||
hasError := c.builder.CreateAnd(inrange1, inrange2, "")
|
inrange1 := c.builder.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
|
||||||
errResult := c.builder.CreateSelect(hasError, c.builder.CreateNot(syscallResult, ""), zero, "syscallError")
|
inrange2 := c.builder.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(c.uintptrType, 0xfffffffffffff000, true), "") // -4096
|
||||||
retval := llvm.Undef(llvm.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
|
hasError := c.builder.CreateAnd(inrange1, inrange2, "")
|
||||||
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
|
errResult := c.builder.CreateSelect(hasError, c.builder.CreateSub(zero, syscallResult, ""), zero, "syscallError")
|
||||||
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
|
retval := llvm.Undef(llvm.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
|
||||||
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
|
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
|
||||||
return retval, nil
|
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
|
||||||
|
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
|
||||||
|
return retval, nil
|
||||||
|
case "darwin":
|
||||||
|
// Return values: r0, r1 uintptr, err Errno
|
||||||
|
// Pseudocode:
|
||||||
|
// var err uintptr
|
||||||
|
// if syscallResult != 0 {
|
||||||
|
// err = syscallResult
|
||||||
|
// }
|
||||||
|
// return syscallResult, 0, err
|
||||||
|
zero := llvm.ConstInt(c.uintptrType, 0, false)
|
||||||
|
hasError := c.builder.CreateICmp(llvm.IntNE, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
|
||||||
|
errResult := c.builder.CreateSelect(hasError, syscallResult, zero, "syscallError")
|
||||||
|
retval := llvm.Undef(llvm.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
|
||||||
|
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
|
||||||
|
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
|
||||||
|
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
|
||||||
|
return retval, nil
|
||||||
|
default:
|
||||||
|
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS+"/"+c.GOARCH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo CFLAGS: -I/usr/lib/llvm-7/include
|
#cgo linux CFLAGS: -I/usr/lib/llvm-7/include
|
||||||
#cgo LDFLAGS: -L/usr/lib/llvm-7/lib -lclang
|
#cgo darwin CFLAGS: -I/usr/local/opt/llvm/include
|
||||||
|
#cgo linux LDFLAGS: -L/usr/lib/llvm-7/lib -lclang
|
||||||
|
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm/lib -lclang -lffi
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
6
main.go
6
main.go
|
@ -22,7 +22,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var commands = map[string]string{
|
var commands = map[string]string{
|
||||||
"ar": "ar",
|
"ar": "llvm-ar",
|
||||||
"clang": "clang-7",
|
"clang": "clang-7",
|
||||||
"ld.lld": "ld.lld-7",
|
"ld.lld": "ld.lld-7",
|
||||||
"wasm-ld": "wasm-ld-7",
|
"wasm-ld": "wasm-ld-7",
|
||||||
|
@ -102,7 +102,9 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
||||||
return errors.New("verification error after interpreting runtime.initAll")
|
return errors.New("verification error after interpreting runtime.initAll")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ApplyFunctionSections() // -ffunction-sections
|
if spec.GOOS != "darwin" {
|
||||||
|
c.ApplyFunctionSections() // -ffunction-sections
|
||||||
|
}
|
||||||
if err := c.Verify(); err != nil {
|
if err := c.Verify(); err != nil {
|
||||||
return errors.New("verification error after applying function sections")
|
return errors.New("verification error after applying function sections")
|
||||||
}
|
}
|
||||||
|
|
43
main_test.go
43
main_test.go
|
@ -10,6 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -53,32 +54,34 @@ func TestCompiler(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Log("running tests for linux/arm...")
|
|
||||||
for _, path := range matches {
|
|
||||||
if path == "testdata/cgo/" {
|
|
||||||
continue // TODO: improve CGo
|
|
||||||
}
|
|
||||||
t.Run(path, func(t *testing.T) {
|
|
||||||
runTest(path, tmpdir, "arm--linux-gnueabi", t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Log("running tests for linux/arm64...")
|
|
||||||
for _, path := range matches {
|
|
||||||
if path == "testdata/cgo/" {
|
|
||||||
continue // TODO: improve CGo
|
|
||||||
}
|
|
||||||
t.Run(path, func(t *testing.T) {
|
|
||||||
runTest(path, tmpdir, "aarch64--linux-gnueabi", t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Log("running tests for emulated cortex-m3...")
|
t.Log("running tests for emulated cortex-m3...")
|
||||||
for _, path := range matches {
|
for _, path := range matches {
|
||||||
t.Run(path, func(t *testing.T) {
|
t.Run(path, func(t *testing.T) {
|
||||||
runTest(path, tmpdir, "qemu", t)
|
runTest(path, tmpdir, "qemu", t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
t.Log("running tests for linux/arm...")
|
||||||
|
for _, path := range matches {
|
||||||
|
if path == "testdata/cgo/" {
|
||||||
|
continue // TODO: improve CGo
|
||||||
|
}
|
||||||
|
t.Run(path, func(t *testing.T) {
|
||||||
|
runTest(path, tmpdir, "arm--linux-gnueabi", t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("running tests for linux/arm64...")
|
||||||
|
for _, path := range matches {
|
||||||
|
if path == "testdata/cgo/" {
|
||||||
|
continue // TODO: improve CGo
|
||||||
|
}
|
||||||
|
t.Run(path, func(t *testing.T) {
|
||||||
|
runTest(path, tmpdir, "aarch64--linux-gnueabi", t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTest(path, tmpdir string, target string, t *testing.T) {
|
func runTest(path, tmpdir string, target string, t *testing.T) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build linux
|
// +build darwin linux
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|
5
src/runtime/os_darwin.go
Обычный файл
5
src/runtime/os_darwin.go
Обычный файл
|
@ -0,0 +1,5 @@
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
const GOOS = "darwin"
|
|
@ -1,4 +1,4 @@
|
||||||
// +build linux
|
// +build darwin linux
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,9 @@ func LoadTarget(target string) (*TargetSpec, error) {
|
||||||
return nil, errors.New("expected a full LLVM target or a custom target in -target flag")
|
return nil, errors.New("expected a full LLVM target or a custom target in -target flag")
|
||||||
}
|
}
|
||||||
goos := tripleSplit[2]
|
goos := tripleSplit[2]
|
||||||
|
if strings.HasPrefix(goos, "darwin") {
|
||||||
|
goos = "darwin"
|
||||||
|
}
|
||||||
goarch := map[string]string{ // map from LLVM arch to Go arch
|
goarch := map[string]string{ // map from LLVM arch to Go arch
|
||||||
"i386": "386",
|
"i386": "386",
|
||||||
"x86_64": "amd64",
|
"x86_64": "amd64",
|
||||||
|
@ -211,11 +214,15 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||||
BuildTags: []string{goos, goarch},
|
BuildTags: []string{goos, goarch},
|
||||||
Compiler: commands["clang"],
|
Compiler: commands["clang"],
|
||||||
Linker: "cc",
|
Linker: "cc",
|
||||||
LDFlags: []string{"-no-pie", "-Wl,--gc-sections"}, // WARNING: clang < 5.0 requires -nopie
|
|
||||||
Objcopy: "objcopy",
|
Objcopy: "objcopy",
|
||||||
GDB: "gdb",
|
GDB: "gdb",
|
||||||
GDBCmds: []string{"run"},
|
GDBCmds: []string{"run"},
|
||||||
}
|
}
|
||||||
|
if goos == "darwin" {
|
||||||
|
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
|
||||||
|
} else {
|
||||||
|
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
||||||
|
}
|
||||||
if goarch != runtime.GOARCH {
|
if goarch != runtime.GOARCH {
|
||||||
// Some educated guesses as to how to invoke helper programs.
|
// Some educated guesses as to how to invoke helper programs.
|
||||||
if goarch == "arm" && goos == "linux" {
|
if goarch == "arm" && goos == "linux" {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче