diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | builder/build.go | 9 | ||||
-rw-r--r-- | builder/picolibc.go | 127 | ||||
-rw-r--r-- | cgo/cgo.go | 5 | ||||
-rw-r--r-- | compileopts/config.go | 6 | ||||
-rw-r--r-- | compileopts/target.go | 4 | ||||
m--------- | lib/picolibc | 0 | ||||
-rw-r--r-- | lib/picolibc-include/picolibc.h | 0 | ||||
-rw-r--r-- | main.go | 19 | ||||
-rw-r--r-- | src/runtime/runtime_arm7tdmi.go | 14 | ||||
-rw-r--r-- | src/runtime/runtime_cortexm.go | 20 | ||||
-rw-r--r-- | src/runtime/runtime_tinygoriscv.go | 19 | ||||
-rw-r--r-- | targets/cortex-m.json | 3 | ||||
-rw-r--r-- | targets/gameboy-advance.json | 2 | ||||
-rw-r--r-- | targets/riscv.json | 2 | ||||
-rw-r--r-- | testdata/cgo/main.go | 7 | ||||
-rw-r--r-- | testdata/cgo/out.txt | 1 |
18 files changed, 195 insertions, 62 deletions
diff --git a/.gitmodules b/.gitmodules index 7e86215ef..af6e1809a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,3 +17,6 @@ [submodule "lib/wasi-libc"] path = lib/wasi-libc url = https://github.com/CraneStation/wasi-libc +[submodule "lib/picolibc"] + path = lib/picolibc + url = https://github.com/keith-packard/picolibc.git @@ -312,6 +312,7 @@ release: tinygo gen-device wasi-libc @mkdir -p build/release/tinygo/lib/CMSIS/CMSIS @mkdir -p build/release/tinygo/lib/compiler-rt/lib @mkdir -p build/release/tinygo/lib/nrfx + @mkdir -p build/release/tinygo/lib/picolibc/newlib/libc @mkdir -p build/release/tinygo/lib/wasi-libc @mkdir -p build/release/tinygo/pkg/armv6m-none-eabi @mkdir -p build/release/tinygo/pkg/armv7m-none-eabi @@ -325,10 +326,19 @@ release: tinygo gen-device wasi-libc @cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt @cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt @cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx + @cp -rp lib/picolibc/newlib/libc/ctype build/release/tinygo/lib/picolibc/newlib/libc + @cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc + @cp -rp lib/picolibc/newlib/libc/locale build/release/tinygo/lib/picolibc/newlib/libc + @cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc + @cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc + @cp -rp lib/picolibc-include build/release/tinygo/lib @cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot @cp -rp src build/release/tinygo/src @cp -rp targets build/release/tinygo/targets - ./build/tinygo build-builtins -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a - ./build/tinygo build-builtins -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a - ./build/tinygo build-builtins -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a + ./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a compiler-rt + ./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a compiler-rt + ./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a compiler-rt + ./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/picolibc.a picolibc + ./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/picolibc.a picolibc + ./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/picolibc.a picolibc tar -czf build/release.tar.gz -C build/release tinygo diff --git a/builder/build.go b/builder/build.go index d3e9fcc7f..85a4dd515 100644 --- a/builder/build.go +++ b/builder/build.go @@ -145,6 +145,15 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri ldflags = append(ldflags, librt) } + // Add libc. + if config.Target.Libc == "picolibc" { + libc, err := Picolibc.Load(config.Triple()) + if err != nil { + return err + } + ldflags = append(ldflags, libc) + } + // Compile extra files. root := goenv.Get("TINYGOROOT") for i, path := range config.ExtraFiles() { diff --git a/builder/picolibc.go b/builder/picolibc.go new file mode 100644 index 000000000..31e2f0530 --- /dev/null +++ b/builder/picolibc.go @@ -0,0 +1,127 @@ +package builder + +import ( + "path/filepath" + + "github.com/tinygo-org/tinygo/goenv" +) + +// Picolibc is a C library for bare metal embedded devices. It was originally +// based on newlib. +var Picolibc = Library{ + name: "picolibc", + cflags: func() []string { + picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc") + return []string{"-Werror", "-Wall", "-std=gnu11", "-D_COMPILING_NEWLIB", "-fshort-enums", "--sysroot=" + picolibcDir, "-I" + picolibcDir + "/tinystdio", "-I" + goenv.Get("TINYGOROOT") + "/lib/picolibc-include"} + }, + sourceDir: "lib/picolibc/newlib/libc", + sources: func(target string) []string { + return picolibcSources + }, +} + +var picolibcSources = []string{ + "string/bcmp.c", + "string/bcopy.c", + "string/bzero.c", + "string/explicit_bzero.c", + "string/ffsl.c", + "string/ffsll.c", + "string/fls.c", + "string/flsl.c", + "string/flsll.c", + "string/gnu_basename.c", + "string/index.c", + "string/memccpy.c", + "string/memchr.c", + "string/memcmp.c", + "string/memcpy.c", + "string/memmem.c", + "string/memmove.c", + "string/mempcpy.c", + "string/memrchr.c", + "string/memset.c", + "string/rawmemchr.c", + "string/rindex.c", + "string/stpcpy.c", + "string/stpncpy.c", + "string/strcasecmp.c", + "string/strcasecmp_l.c", + "string/strcasestr.c", + "string/strcat.c", + "string/strchr.c", + "string/strchrnul.c", + "string/strcmp.c", + "string/strcoll.c", + "string/strcoll_l.c", + "string/strcpy.c", + "string/strcspn.c", + "string/strdup.c", + "string/strerror.c", + "string/strerror_r.c", + "string/strlcat.c", + "string/strlcpy.c", + "string/strlen.c", + "string/strlwr.c", + "string/strncasecmp.c", + "string/strncasecmp_l.c", + "string/strncat.c", + "string/strncmp.c", + "string/strncpy.c", + "string/strndup.c", + "string/strnlen.c", + "string/strnstr.c", + "string/strpbrk.c", + "string/strrchr.c", + "string/strsep.c", + "string/strsignal.c", + "string/strspn.c", + "string/strstr.c", + "string/strtok.c", + "string/strtok_r.c", + "string/strupr.c", + "string/strverscmp.c", + "string/strxfrm.c", + "string/strxfrm_l.c", + "string/swab.c", + "string/timingsafe_bcmp.c", + "string/timingsafe_memcmp.c", + "string/u_strerr.c", + "string/wcpcpy.c", + "string/wcpncpy.c", + "string/wcscasecmp.c", + "string/wcscasecmp_l.c", + "string/wcscat.c", + "string/wcschr.c", + "string/wcscmp.c", + "string/wcscoll.c", + "string/wcscoll_l.c", + "string/wcscpy.c", + "string/wcscspn.c", + "string/wcsdup.c", + "string/wcslcat.c", + "string/wcslcpy.c", + "string/wcslen.c", + "string/wcsncasecmp.c", + "string/wcsncasecmp_l.c", + "string/wcsncat.c", + "string/wcsncmp.c", + "string/wcsncpy.c", + "string/wcsnlen.c", + "string/wcspbrk.c", + "string/wcsrchr.c", + "string/wcsspn.c", + "string/wcsstr.c", + "string/wcstok.c", + "string/wcswidth.c", + "string/wcsxfrm.c", + "string/wcsxfrm_l.c", + "string/wcwidth.c", + "string/wmemchr.c", + "string/wmemcmp.c", + "string/wmemcpy.c", + "string/wmemmove.c", + "string/wmempcpy.c", + "string/wmemset.c", + "string/xpg_strerror_r.c", +} diff --git a/cgo/cgo.go b/cgo/cgo.go index 58aaed81c..d6470a522 100644 --- a/cgo/cgo.go +++ b/cgo/cgo.go @@ -170,6 +170,11 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string enums: map[string]enumInfo{}, } + // Disable _FORTIFY_SOURCE as it causes problems on macOS. + // Note that it is only disabled for memcpy (etc) calls made from Go, which + // have better alternatives anyway. + cflags = append(cflags, "-D_FORTIFY_SOURCE=0") + // Add a new location for the following file. generatedTokenPos := p.fset.AddFile(dir+"/!cgo.go", -1, 0) generatedTokenPos.SetLines([]int{0}) diff --git a/compileopts/config.go b/compileopts/config.go index d3f4bd1d0..e30679080 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -5,6 +5,7 @@ package compileopts import ( "errors" "fmt" + "path/filepath" "regexp" "strconv" "strings" @@ -163,6 +164,11 @@ func (c *Config) CFlags() []string { for _, flag := range c.Target.CFlags { cflags = append(cflags, strings.Replace(flag, "{root}", goenv.Get("TINYGOROOT"), -1)) } + if c.Target.Libc == "picolibc" { + root := goenv.Get("TINYGOROOT") + cflags = append(cflags, "--sysroot="+filepath.Join(root, "lib", "picolibc", "newlib", "libc")) + cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include")) + } return cflags } diff --git a/compileopts/target.go b/compileopts/target.go index 637712c83..2071c73a5 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -32,6 +32,7 @@ type TargetSpec struct { Compiler string `json:"compiler"` Linker string `json:"linker"` RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt) + Libc string `json:"libc"` CFlags []string `json:"cflags"` LDFlags []string `json:"ldflags"` LinkerScript string `json:"linkerscript"` @@ -84,6 +85,9 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) { if spec2.RTLib != "" { spec.RTLib = spec2.RTLib } + if spec2.Libc != "" { + spec.Libc = spec2.Libc + } spec.CFlags = append(spec.CFlags, spec2.CFlags...) spec.LDFlags = append(spec.LDFlags, spec2.LDFlags...) if spec2.LinkerScript != "" { diff --git a/lib/picolibc b/lib/picolibc new file mode 160000 +Subproject 80528c684b10aaee977397e7eb40c4784e6dc43 diff --git a/lib/picolibc-include/picolibc.h b/lib/picolibc-include/picolibc.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/lib/picolibc-include/picolibc.h @@ -786,7 +786,7 @@ func main() { } err := Build(pkgName, *outpath, options) handleCompilerError(err) - case "build-builtins": + case "build-library": // Note: this command is only meant to be used while making a release! if *outpath == "" { fmt.Fprintln(os.Stderr, "No output filename supplied (-o).") @@ -796,7 +796,22 @@ func main() { if *target == "" { fmt.Fprintln(os.Stderr, "No target (-target).") } - path, err := builder.CompilerRT.Load(*target) + if flag.NArg() != 1 { + fmt.Fprintf(os.Stderr, "Build-library only accepts exactly one library name as argument, %d given\n", flag.NArg()) + usage() + os.Exit(1) + } + var lib *builder.Library + switch name := flag.Arg(0); name { + case "compiler-rt": + lib = &builder.CompilerRT + case "picolibc": + lib = &builder.Picolibc + default: + fmt.Fprintf(os.Stderr, "Unknown library: %s\n", name) + os.Exit(1) + } + path, err := lib.Load(*target) handleCompilerError(err) copyFile(path, *outpath) case "flash", "gdb": diff --git a/src/runtime/runtime_arm7tdmi.go b/src/runtime/runtime_arm7tdmi.go index d7629ad6d..b292f6468 100644 --- a/src/runtime/runtime_arm7tdmi.go +++ b/src/runtime/runtime_arm7tdmi.go @@ -76,17 +76,3 @@ func abort() { for { } } - -// Implement memset for LLVM and compiler-rt. -//go:export memset -func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) { - for i := uintptr(0); i < size; i++ { - *(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = c - } -} - -// Implement memmove for LLVM and compiler-rt. -//go:export memmove -func libc_memmove(dst, src unsafe.Pointer, size uintptr) { - memmove(dst, src, size) -} diff --git a/src/runtime/runtime_cortexm.go b/src/runtime/runtime_cortexm.go index 04b34039a..46f836770 100644 --- a/src/runtime/runtime_cortexm.go +++ b/src/runtime/runtime_cortexm.go @@ -95,23 +95,3 @@ func handleHardFault(sp *interruptStack) { println() abort() } - -// Implement memset for LLVM and compiler-rt. -//go:export memset -func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) { - for i := uintptr(0); i < size; i++ { - *(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = c - } -} - -// Implement memmove for LLVM and compiler-rt. -//go:export memmove -func libc_memmove(dst, src unsafe.Pointer, size uintptr) { - memmove(dst, src, size) -} - -// Implement memcpy for LLVM and compiler-rt. -//go:export memcpy -func libc_memcpy(dst, src unsafe.Pointer, size uintptr) { - memcpy(dst, src, size) -} diff --git a/src/runtime/runtime_tinygoriscv.go b/src/runtime/runtime_tinygoriscv.go deleted file mode 100644 index 691680b44..000000000 --- a/src/runtime/runtime_tinygoriscv.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build tinygo.riscv - -package runtime - -import "unsafe" - -// Implement memset for LLVM. -//go:export memset -func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) { - for i := uintptr(0); i < size; i++ { - *(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = c - } -} - -// Implement memmove for LLVM. -//go:export memmove -func libc_memmove(dst, src unsafe.Pointer, size uintptr) { - memmove(dst, src, size) -} diff --git a/targets/cortex-m.json b/targets/cortex-m.json index 513a84634..979c09d1f 100644 --- a/targets/cortex-m.json +++ b/targets/cortex-m.json @@ -7,13 +7,12 @@ "scheduler": "tasks", "linker": "ld.lld", "rtlib": "compiler-rt", + "libc": "picolibc", "cflags": [ "-Oz", "-mthumb", "-Werror", "-fshort-enums", - "-nostdlibinc", - "-Wno-macro-redefined", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections" ], diff --git a/targets/gameboy-advance.json b/targets/gameboy-advance.json index 2ef4f8d1f..f7ac76ebb 100644 --- a/targets/gameboy-advance.json +++ b/targets/gameboy-advance.json @@ -7,6 +7,7 @@ "compiler": "clang", "linker": "ld.lld", "rtlib": "compiler-rt", + "libc": "picolibc", "cflags": [ "-g", "--target=thumb4-none-eabi", @@ -14,7 +15,6 @@ "-Oz", "-Werror", "-fshort-enums", - "-Wno-macro-redefined", "-Qunused-arguments", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections" diff --git a/targets/riscv.json b/targets/riscv.json index f96354008..f74c1767d 100644 --- a/targets/riscv.json +++ b/targets/riscv.json @@ -7,13 +7,13 @@ "compiler": "clang", "linker": "ld.lld", "rtlib": "compiler-rt", + "libc": "picolibc", "cflags": [ "--target=riscv32--none", "-march=rv32imac", "-mabi=ilp32", "-Os", "-Werror", - "-nostdinc", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections" ], diff --git a/testdata/cgo/main.go b/testdata/cgo/main.go index 41bc6892c..557dea5cf 100644 --- a/testdata/cgo/main.go +++ b/testdata/cgo/main.go @@ -4,6 +4,7 @@ package main int fortytwo(void); #include "main.h" int mul(int, int); +#include <string.h> */ import "C" @@ -109,6 +110,12 @@ func main() { var _ C.option3_t = C.option3A println("option 2A:", C.option2A) println("option 3A:", C.option3A) + + // libc: test whether C functions work at all. + buf1 := []byte("foobar\x00") + buf2 := make([]byte, len(buf1)) + C.strcpy((*C.char)(unsafe.Pointer(&buf2[0])), (*C.char)(unsafe.Pointer(&buf1[0]))) + println("copied string:", string(buf2[:C.strlen((*C.char)(unsafe.Pointer(&buf2[0])))])) } func printUnion(union C.joined_t) C.joined_t { diff --git a/testdata/cgo/out.txt b/testdata/cgo/out.txt index 73cb2b990..fcb688467 100644 --- a/testdata/cgo/out.txt +++ b/testdata/cgo/out.txt @@ -55,3 +55,4 @@ option F: 11 option G: 12 option 2A: 20 option 3A: 21 +copied string: foobar |