Compare commits

..

6 Commits

Author SHA1 Message Date
Ayke van Laethem b5ad81c884 all: update to version 0.26.0 2022-09-29 15:05:15 +02:00
deadprogram c2fb1e776a testdata: increase timings used for timers test to try to avoid race condition errors on macOS CI
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-09-28 21:55:37 +02:00
Ayke van Laethem 895c542076 builder: do not ignore debug info on baremetal targets
Since https://github.com/tinygo-org/tinygo/pull/3200, `-no-debug` would
ignore debug info for some linkers. Example:

    $ tinygo build -o test.elf -target=arduino -no-debug examples/blinky1
    $ objdump -h test.elf

    test.elf:       file format elf32-avr

    Sections:
    Idx Name            Size     VMA      LMA      Type
      0                 00000000 00000000 00000000
      1 .text           000004e0 00000000 00000000 TEXT
      2 .trampolines    00000000 000004e0 000004e0 TEXT
      3 .stack          00000200 00800100 00800100 BSS
      4 .data           0000004c 00800300 000004e0 DATA
      5 .bss            000000a9 0080034c 0000052c BSS
      6 .debug_loc      00001bf0 00000000 00000000 DEBUG
      7 .debug_abbrev   000004ed 00000000 00000000 DEBUG
      8 .debug_info     00004176 00000000 00000000 DEBUG
      9 .debug_ranges   00000150 00000000 00000000 DEBUG
     10 .debug_str      0000206e 00000000 00000000 DEBUG
     11 .debug_pubnames 000024bf 00000000 00000000 DEBUG
     12 .debug_pubtypes 000004ca 00000000 00000000 DEBUG
     13 .debug_line     0000193c 00000000 00000000 DEBUG
     14 .debug_aranges  0000002c 00000000 00000000 DEBUG
     15 .debug_rnglists 00000015 00000000 00000000 DEBUG
     16 .debug_line_str 00000082 00000000 00000000 DEBUG
     17 .shstrtab       000000d9 00000000 00000000
     18 .symtab         000006d0 00000000 00000000
     19 .strtab         00000607 00000000 00000000

This shows that even though `-no-debug` is supplied, debug information
is emitted in the ELF file.

With this change, debug information is not stripped when TinyGo doesn't
know how to do it:

    $ tinygo build -o test.elf -target=arduino -no-debug examples/blinky1
    error: cannot remove debug information: unknown linker: avr-gcc

(This issue will eventually be fixed by moving to `ld.lld`).
2022-09-28 19:18:11 +02:00
Adrian Cole e91fae5756 compileopts: silently succeed when there's no debug info to strip
Before, on the baremetal target or MacOS, we errored if the user
provided configuration to strip debug info.

Ex.
```bash
$ $ tinygo build -o main.go  -scheduler=none --no-debug  main.go
error: cannot remove debug information: MacOS doesn't store debug info in the executable by default
```

This is a poor experience which results in having OS-specific CLI
behavior. Silently succeeding is good keeping with the Linux philosophy
and less distracting than logging the same without failing.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-09-27 08:16:35 +02:00
Ayke van Laethem f52ecf3054 machine: use NoPin constant where appropriate
In some cases, regular integers were used. But we have a constant to
explicitly say these pins are undefined: `NoPin`. So use this.

A better solution would be to not require these constants, like with the
proposal in https://github.com/tinygo-org/tinygo/issues/3152. This
change is just a slight improvement over the current state.
2022-09-26 20:44:47 +02:00
Crypt Keeper 725864d8dc cgo: fixes panic when FuncType.Results is nil (#3136)
* cgo: fixes panic when FuncType.Results is nil

FuncType.Results can be nil. This fixes the comparison and backfills
relevant tests.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Ayke <aykevanlaethem@gmail.com>
2022-09-26 19:08:23 +02:00
13 changed files with 228 additions and 305 deletions
-2
View File
@@ -236,8 +236,6 @@ jobs:
run: |
make ASSERT=1
echo "$(pwd)/build" >> $GITHUB_PATH
- name: Test machine package
run: make check-machine
- name: Test stdlib packages
run: make tinygo-test
- name: Install Xtensa toolchain
+84
View File
@@ -1,3 +1,87 @@
0.26.0
---
* **general**
- remove support for LLVM 13
- remove calls to deprecated ioutil package
- move from `os.IsFoo` to `errors.Is(err, ErrFoo)`
- fix for builds using an Android host
- make interp timeout configurable from command line
- ignore ports with VID/PID if there is no candidates
- drop support for Go 1.16 and Go 1.17
- update serial package to v1.3.5 for latest bugfixes
- remove GOARM from `tinygo info`
- add flag for setting the goroutine stack size
- add serial port monitoring functionality
* **compiler**
- `cgo`: implement support for static functions
- `cgo`: fix panic when FuncType.Results is nil
- `compiler`: add aliases for `edwards25519/field.feMul` and `field.feSquare`
- `compiler`: fix incorrect DWARF type in some generic parameters
- `compiler`: use LLVM math builtins everywhere
- `compiler`: replace some math operation bodies with LLVM intrinsics
- `compiler`: replace math aliases with intrinsics
- `compiler`: fix `unsafe.Sizeof` for chan and map values
- `compileopts`: use tags parser from buildutil
- `compileopts`: use backticks for regexp to avoid extra escapes
- `compileopts`: fail fast on duplicate values in target field slices
- `compileopts`: fix windows/arm target triple
- `compileopts`: improve error handling when loading target/*.json
- `compileopts`: add support for stlink-dap programmer
- `compileopts`: do not complain about `-no-debug` on MacOS
- `goenv`: support `GOOS=android`
- `interp`: fix reading from external global
- `loader`: fix link error for `crypto/internal/boring/sig.StandardCrypto`
* **standard library**
- rename assembly files to .S extension
- `machine`: add PWM peripheral comments to pins
- `machine`: improve UARTParity slightly
- `machine`: do not export DFU_MAGIC_* constants on nrf52840
- `machine`: rename `PinInputPullUp`/`PinInputPullDown`
- `machine`: add `KHz`, `MHz`, `GHz` constants, deprecate `TWI_FREQ_*` constants
- `machine`: remove level triggered pin interrupts
- `machine`: do not expose `RESET_MAGIC_VALUE`
- `machine`: use `NoPin` constant where appropriate (instead of `0` for example)
- `net`: sync net.go with Go 1.18 stdlib
- `os`: add `SyscallError.Timeout`
- `os`: add `ErrProcessDone` error
- `reflect`: implement `CanInterface` and fix string `Index`
- `runtime`: make `MemStats` available to leaking collector
- `runtime`: add `MemStats.TotalAlloc`
- `runtime`: add `MemStats.Mallocs` and `Frees`
- `runtime`: add support for `time.NewTimer` and `time.NewTicker`
- `runtime`: implement `resetTimer`
- `runtime`: ensure some headroom for the GC to run
- `runtime`: make gc and scheduler asserts settable with build tags
- `runtime/pprof`: add `WriteHeapProfile`
- `runtime/pprof`: `runtime/trace`: stub some additional functions
- `sync`: implement `Map.LoadAndDelete`
- `syscall`: group WASI consts by purpose
- `syscall`: add WASI `{D,R}SYNC`, `NONBLOCK` FD flags
- `syscall`: add ENOTCONN on darwin
- `testing`: add support for -benchmem
* **targets**
- remove USB vid/pid pair of bootloader
- `esp32c3`: remove unused `UARTStopBits` constants
- `nrf`: implement `GetRNG` function
- `nrf`: `rp2040`: add `machine.ReadTemperature`
- `nrf52`: cleanup s140v6 and s140v7 uf2 targets
- `rp2040`: implement semi-random RNG based on ROSC based on pico-sdk
- `wasm`: add summary of wasm examples and fix callback bug
- `wasm`: do not allow undefined symbols (`--allow-undefined`)
- `wasm`: make sure buffers returned by `malloc` are kept until `free` is called
- `windows`: save and restore xmm registers when switching goroutines
* **boards**
- add Pimoroni's Tufty2040
- add XIAO ESP32C3
- add Adafruit QT2040
- add Adafruit QT Py RP2040
- `esp32c3-12f`: `matrixportal-m4`: `p1am-100`: remove duplicate build tags
- `hifive1-qemu`: remove this emulated board
- `wioterminal`: add UART3 for RTL8720DN
- `xiao-ble`: fix usbpid
0.25.0
---
-12
View File
@@ -267,18 +267,6 @@ tinygo:
test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# Check whether the machine package matches the documentation.
# TODO: improve `tinygo targets` so it doesn't return these invalid targets.
CHECK_MACHINE_EXCULDE = \
cortex-m-qemu \
particle-3rd-gen \
riscv-qemu \
riscv64-qemu \
rp2040 \
$(nil)
check-machine:
$(GO) run ./tools/machinecheck $(filter-out $(CHECK_MACHINE_EXCULDE),$(shell $(TINYGO) targets))
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
TEST_PACKAGES_SLOW = \
compress/bzip2 \
+11 -14
View File
@@ -700,21 +700,18 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Add embedded files.
linkerDependencies = append(linkerDependencies, embedFileObjects...)
// Determine whether the compilation configuration would result in debug
// (DWARF) information in the object files.
var hasDebug = true
if config.GOOS() == "darwin" {
// Debug information isn't stored in the binary itself on MacOS but
// is left in the object files by default. The binary does store the
// path to these object files though.
hasDebug = false
}
// Strip debug information with -no-debug.
if !config.Debug() {
for _, tag := range config.BuildTags() {
if tag == "baremetal" {
// Don't use -no-debug on baremetal targets. It makes no sense:
// the debug information isn't flashed to the device anyway.
return fmt.Errorf("stripping debug information is unnecessary for baremetal targets")
}
}
if config.GOOS() == "darwin" {
// Debug information isn't stored in the binary itself on MacOS but
// is left in the object files by default. The binary does store the
// path to these object files though.
return errors.New("cannot remove debug information: MacOS doesn't store debug info in the executable by default")
}
if hasDebug && !config.Debug() {
if config.Target.Linker == "wasm-ld" {
// Don't just strip debug information, also compress relocations
// while we're at it. Relocations can only be compressed when debug
+3
View File
@@ -948,6 +948,9 @@ func (p *cgoPackage) isEquivalentAST(a, b ast.Node) bool {
if !ok {
return false
}
if node == nil || b == nil {
return node == b
}
if len(node.List) != len(b.List) {
return false
}
+78
View File
@@ -115,6 +115,84 @@ func TestCGo(t *testing.T) {
}
}
func Test_cgoPackage_isEquivalentAST(t *testing.T) {
fieldA := &ast.Field{Type: &ast.BasicLit{Kind: token.STRING, Value: "a"}}
fieldB := &ast.Field{Type: &ast.BasicLit{Kind: token.STRING, Value: "b"}}
listOfFieldA := &ast.FieldList{List: []*ast.Field{fieldA}}
listOfFieldB := &ast.FieldList{List: []*ast.Field{fieldB}}
funcDeclA := &ast.FuncDecl{Name: &ast.Ident{Name: "a"}, Type: &ast.FuncType{Params: &ast.FieldList{}, Results: listOfFieldA}}
funcDeclB := &ast.FuncDecl{Name: &ast.Ident{Name: "b"}, Type: &ast.FuncType{Params: &ast.FieldList{}, Results: listOfFieldB}}
funcDeclNoResults := &ast.FuncDecl{Name: &ast.Ident{Name: "C"}, Type: &ast.FuncType{Params: &ast.FieldList{}}}
testCases := []struct {
name string
a, b ast.Node
expected bool
}{
{
name: "both nil",
expected: true,
},
{
name: "not same type",
a: fieldA,
b: &ast.FuncDecl{},
expected: false,
},
{
name: "Field same",
a: fieldA,
b: fieldA,
expected: true,
},
{
name: "Field different",
a: fieldA,
b: fieldB,
expected: false,
},
{
name: "FuncDecl Type Results nil",
a: funcDeclNoResults,
b: funcDeclNoResults,
expected: true,
},
{
name: "FuncDecl Type Results same",
a: funcDeclA,
b: funcDeclA,
expected: true,
},
{
name: "FuncDecl Type Results different",
a: funcDeclA,
b: funcDeclB,
expected: false,
},
{
name: "FuncDecl Type Results a nil",
a: funcDeclNoResults,
b: funcDeclB,
expected: false,
},
{
name: "FuncDecl Type Results b nil",
a: funcDeclA,
b: funcDeclNoResults,
expected: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
p := &cgoPackage{}
if got := p.isEquivalentAST(tc.a, tc.b); tc.expected != got {
t.Errorf("expected %v, got %v", tc.expected, got)
}
})
}
}
// simpleImporter implements the types.Importer interface, but only allows
// importing the unsafe package.
type simpleImporter struct {
+2 -2
View File
@@ -377,8 +377,8 @@ func (c *Config) VerifyIR() bool {
}
// Debug returns whether debug (DWARF) information should be retained by the
// linker. By default, debug information is retained but it can be removed with
// the -no-debug flag.
// linker. By default, debug information is retained, but it can be removed
// with the -no-debug flag.
func (c *Config) Debug() bool {
return c.Options.Debug
}
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const Version = "0.26.0-dev"
const Version = "0.26.0"
var (
// This variable is set at build time using -ldflags parameters.
+5 -5
View File
@@ -52,8 +52,8 @@ const (
I2C0_SDA_PIN = GPIO20
I2C0_SCL_PIN = GPIO21
I2C1_SDA_PIN = 31 // not pinned out
I2C1_SCL_PIN = 31 // not pinned out
I2C1_SDA_PIN = NoPin // not pinned out
I2C1_SCL_PIN = NoPin // not pinned out
)
// SPI default pins
@@ -65,9 +65,9 @@ const (
// Default Serial In Bus 1 for SPI communications
SPI1_SDI_PIN = GPIO28 // Rx
SPI0_SCK_PIN = 31 // not pinned out
SPI0_SDO_PIN = 31 // not pinned out
SPI0_SDI_PIN = 31 // not pinned out
SPI0_SCK_PIN = NoPin // not pinned out
SPI0_SDO_PIN = NoPin // not pinned out
SPI0_SDI_PIN = NoPin // not pinned out
)
// UART pins
+8 -8
View File
@@ -18,15 +18,15 @@ const (
// MDBT50Q-RX dongle does not have pins broken out for the peripherals below,
// however the machine_nrf*.go implementations of I2C/SPI/etc expect the pin
// constants to be defined, so we are defining them all as 0
// constants to be defined, so we are defining them all as NoPin
const (
UART_TX_PIN = 0
UART_RX_PIN = 0
SDA_PIN = 0
SCL_PIN = 0
SPI0_SCK_PIN = 0
SPI0_SDO_PIN = 0
SPI0_SDI_PIN = 0
UART_TX_PIN = NoPin
UART_RX_PIN = NoPin
SDA_PIN = NoPin
SCL_PIN = NoPin
SPI0_SCK_PIN = NoPin
SPI0_SDO_PIN = NoPin
SPI0_SDI_PIN = NoPin
)
// USB CDC identifiers
+25 -25
View File
@@ -4,51 +4,51 @@ import "time"
func main() {
// Test ticker.
ticker := time.NewTicker(time.Millisecond * 250)
ticker := time.NewTicker(time.Millisecond * 500)
println("waiting on ticker")
go func() {
time.Sleep(time.Millisecond * 125)
println(" - after 125ms")
time.Sleep(time.Millisecond * 250)
println(" - after 375ms")
time.Sleep(time.Millisecond * 250)
println(" - after 625ms")
time.Sleep(time.Millisecond * 150)
println(" - after 150ms")
time.Sleep(time.Millisecond * 200)
println(" - after 200ms")
time.Sleep(time.Millisecond * 300)
println(" - after 300ms")
}()
<-ticker.C
println("waited on ticker at 250ms")
<-ticker.C
println("waited on ticker at 500ms")
<-ticker.C
println("waited on ticker at 1000ms")
ticker.Stop()
time.Sleep(time.Millisecond * 500)
time.Sleep(time.Millisecond * 750)
select {
case <-ticker.C:
println("fail: ticker should have stopped!")
default:
println("ticker was stopped (didn't send anything after 500ms)")
println("ticker was stopped (didn't send anything after 750ms)")
}
timer := time.NewTimer(time.Millisecond * 250)
timer := time.NewTimer(time.Millisecond * 500)
println("waiting on timer")
go func() {
time.Sleep(time.Millisecond * 125)
println(" - after 125ms")
time.Sleep(time.Millisecond * 250)
println(" - after 250ms")
time.Sleep(time.Millisecond * 200)
println(" - after 200ms")
time.Sleep(time.Millisecond * 400)
println(" - after 400ms")
}()
<-timer.C
println("waited on timer at 250ms")
time.Sleep(time.Millisecond * 250)
println("waited on timer at 500ms")
time.Sleep(time.Millisecond * 500)
reset := timer.Reset(time.Millisecond * 250)
reset := timer.Reset(time.Millisecond * 500)
println("timer reset:", reset)
println("waiting on timer")
go func() {
time.Sleep(time.Millisecond * 125)
println(" - after 125ms")
time.Sleep(time.Millisecond * 250)
println(" - after 250ms")
time.Sleep(time.Millisecond * 200)
println(" - after 200ms")
time.Sleep(time.Millisecond * 400)
println(" - after 400ms")
}()
<-timer.C
println("waited on timer at 250ms")
time.Sleep(time.Millisecond * 250)
println("waited on timer at 500ms")
time.Sleep(time.Millisecond * 500)
}
+11 -11
View File
@@ -1,16 +1,16 @@
waiting on ticker
- after 125ms
waited on ticker at 250ms
- after 375ms
- after 150ms
- after 200ms
waited on ticker at 500ms
- after 625ms
ticker was stopped (didn't send anything after 500ms)
- after 300ms
waited on ticker at 1000ms
ticker was stopped (didn't send anything after 750ms)
waiting on timer
- after 125ms
waited on timer at 250ms
- after 250ms
- after 200ms
waited on timer at 500ms
- after 400ms
timer reset: false
waiting on timer
- after 125ms
waited on timer at 250ms
- after 250ms
- after 200ms
waited on timer at 500ms
- after 400ms
-225
View File
@@ -1,225 +0,0 @@
package main
// This file runs some checks on the machine package, to make sure it matches
// the documentation and that it is internally consistent between targets.
import (
"fmt"
"go/ast"
"go/scanner"
"go/token"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/packages"
)
// Constants that are documented and always have a particular type.
var knownConsts = map[string]string{
// Chip name, something like "nrf51" or "STM32F429".
"Device": "untyped string",
// Generic constants.
"KHz": "untyped int",
"MHz": "untyped int",
"GHz": "untyped int",
// Pin mode types for machine.PinConfig.
"PinInput": "machine.PinMode",
"PinOutput": "machine.PinMode",
"PinInputPullup": "machine.PinMode",
"PinInputPulldown": "machine.PinMode",
// Pin change events for pin interrupts.
"PinRising": "machine.PinChange",
"PinFalling": "machine.PinChange",
"PinToggle": "machine.PinChange",
// UART parity
"ParityNone": "machine.UARTParity",
"ParityEven": "machine.UARTParity",
"ParityOdd": "machine.UARTParity",
// SPI modes
"Mode0": "untyped int",
"Mode1": "untyped int",
"Mode2": "untyped int",
"Mode3": "untyped int",
// Board specific constants.
"HasLowFrequencyCrystal": "untyped bool", // for nrf boards
}
func main() {
targets := os.Args[1:]
// Start worker goroutines to run checkTarget.
results := make(map[string]chan []error)
for _, target := range targets {
results[target] = make(chan []error, 1)
}
targetsChan := make(chan string)
for i := 0; i < runtime.NumCPU(); i++ {
go func() {
for target := range targetsChan {
errs := checkTarget(target)
if len(errs) != 0 {
results[target] <- errs
}
close(results[target])
}
}()
}
// Check all targets.
go func() {
for _, target := range targets {
targetsChan <- target
}
}()
// Read the result of each check.
failedTargets := 0
for _, target := range targets {
errs := <-results[target]
if len(errs) != 0 {
failedTargets++
fmt.Printf("found errors for %s:\n", target)
for _, err := range errs {
fmt.Println(err)
}
fmt.Println()
}
}
if failedTargets != 0 {
fmt.Printf("Failed checks for %d out of %d targets.\n", failedTargets, len(targets))
os.Exit(1)
}
}
// Check whether the machine package of the given targets is valid.
func checkTarget(target string) []error {
// Load target configuration.
options := &compileopts.Options{
Target: target,
}
spec, err := compileopts.LoadTarget(options)
if err != nil {
return []error{err}
}
config := &compileopts.Config{Options: options, Target: spec}
// Load the package.
goroot, err := loader.GetCachedGoroot(config)
if err != nil {
return []error{err}
}
cfg := &packages.Config{
Env: append(os.Environ(),
"GOOS="+config.GOOS(),
"GOARCH="+config.GOARCH(),
"GOROOT="+goroot,
),
BuildFlags: []string{
"-tags=" + strings.Join(spec.BuildTags, " "),
},
Mode: packages.NeedSyntax | packages.NeedTypes,
}
pkgs, err := packages.Load(cfg, "machine")
if err != nil {
return []error{err}
}
pkg := pkgs[0]
if len(pkg.Errors) != 0 {
var errors []error
for _, err := range pkg.Errors {
errors = append(errors, err)
}
return errors
}
// Check the package!
checker := Checker{
goroot: goroot,
pkg: pkg,
}
for _, file := range pkg.Syntax {
if checker.getPosition(file.Package).Filename == "i2s.go" {
// TODO: check I2S.
continue
}
for _, decl := range file.Decls {
switch decl := decl.(type) {
case *ast.GenDecl:
if isDeprecated(decl.Doc.Text()) {
// Don't check deprecated declarations. They will be removed
// with TinyGo 1.0.
continue
}
switch decl.Tok {
case token.CONST:
for _, spec := range decl.Specs {
spec := spec.(*ast.ValueSpec)
for _, name := range spec.Names {
if !ast.IsExported(name.Name) {
continue
}
checker.checkConst(spec, name)
}
}
}
}
}
}
return checker.errors
}
// Return whether the comment is for a deprecated declaration.
// The convention is explained here:
// https://github.com/golang/go/wiki/Deprecated
func isDeprecated(comment string) bool {
for _, line := range strings.Split(comment, "\n") {
if strings.HasPrefix(line, "Deprecated: ") {
return true
}
}
return false
}
type Checker struct {
goroot string
pkg *packages.Package
errors []error
}
// Check whether a constant declaration follows the documentation.
func (c *Checker) checkConst(spec *ast.ValueSpec, name *ast.Ident) {
t := c.pkg.Types.Scope().Lookup(name.Name).Type()
if knownConsts[name.Name] == t.String() {
return
}
switch {
case t.String() == "machine.Pin":
// Pins have all kinds of names. They might need some checking, but
// right now all pin names are fine.
default:
c.errors = append(c.errors, scanner.Error{
Pos: c.getPosition(name.NamePos),
Msg: fmt.Sprintf("unknown name: %-20s (type %s)", name.Name, t.String()),
})
}
}
func (c *Checker) getPosition(pos token.Pos) token.Position {
position := c.pkg.Fset.Position(pos)
if newpath, err := filepath.Rel(filepath.Join(c.goroot, "src/machine"), position.Filename); err == nil {
position.Filename = newpath
}
return position
}