Skip to content

Commit dc6b74c

Browse files
committed
all: include picolibc for bare metal targets
This is necessary for better CGo support on bare metal. Existing libraries expect to be able to include parts of libc and expect to be able to link to those symbols. Because with this all targets have a working libc, it is now possible to add tests to check that a libc in fact works basically. Not all parts of picolibc are included, such as the math or stdio parts. These should be added later, when needed. This commit also avoids the need for the custom memcpy/memset/memcmp symbols that are sometimes emitted by LLVM. The C library will take care of that.
1 parent 2a6433f commit dc6b74c

File tree

17 files changed

+188
-62
lines changed

17 files changed

+188
-62
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@
1717
[submodule "lib/wasi-libc"]
1818
path = lib/wasi-libc
1919
url = https://github.com/CraneStation/wasi-libc
20+
[submodule "lib/picolibc"]
21+
path = lib/picolibc
22+
url = https://github.com/keith-packard/picolibc.git

Makefile

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ release: tinygo gen-device wasi-libc
279279
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
280280
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
281281
@mkdir -p build/release/tinygo/lib/nrfx
282+
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
282283
@mkdir -p build/release/tinygo/lib/wasi-libc
283284
@mkdir -p build/release/tinygo/pkg/armv6m-none-eabi
284285
@mkdir -p build/release/tinygo/pkg/armv7m-none-eabi
@@ -292,10 +293,16 @@ release: tinygo gen-device wasi-libc
292293
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
293294
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
294295
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
296+
@cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc
297+
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
298+
@cp -rp lib/picolibc-include build/release/tinygo/lib
295299
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
296300
@cp -rp src build/release/tinygo/src
297301
@cp -rp targets build/release/tinygo/targets
298-
./build/tinygo build-builtins -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a
299-
./build/tinygo build-builtins -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a
300-
./build/tinygo build-builtins -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a
302+
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a compiler-rt
303+
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a compiler-rt
304+
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a compiler-rt
305+
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/picolibc.a picolibc
306+
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/picolibc.a picolibc
307+
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/picolibc.a picolibc
301308
tar -czf build/release.tar.gz -C build/release tinygo

builder/build.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,15 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
144144
ldflags = append(ldflags, librt)
145145
}
146146

147+
// Add libc.
148+
if config.Target.Libc == "picolibc" {
149+
libc, err := Picolibc.Load(config.Triple())
150+
if err != nil {
151+
return err
152+
}
153+
ldflags = append(ldflags, libc)
154+
}
155+
147156
// Compile extra files.
148157
root := goenv.Get("TINYGOROOT")
149158
for i, path := range config.ExtraFiles() {

builder/picolibc.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package builder
2+
3+
import (
4+
"path/filepath"
5+
6+
"github.com/tinygo-org/tinygo/goenv"
7+
)
8+
9+
// Picolibc is a C library for bare metal embedded devices. It was originally
10+
// based on newlib.
11+
var Picolibc = Library{
12+
name: "picolibc",
13+
cflags: func() []string {
14+
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc")
15+
return []string{"-Werror", "-Wall", "-std=gnu11", "-D_COMPILING_NEWLIB", "-fshort-enums", "--sysroot=" + picolibcDir, "-I" + picolibcDir + "/tinystdio", "-I" + goenv.Get("TINYGOROOT") + "/lib/picolibc-include"}
16+
},
17+
sourceDir: "lib/picolibc/newlib/libc",
18+
sources: func(target string) []string {
19+
return picolibcSources
20+
},
21+
}
22+
23+
var picolibcSources = []string{
24+
"string/bcmp.c",
25+
"string/bcopy.c",
26+
"string/bzero.c",
27+
"string/explicit_bzero.c",
28+
"string/ffsl.c",
29+
"string/ffsll.c",
30+
"string/fls.c",
31+
"string/flsl.c",
32+
"string/flsll.c",
33+
"string/gnu_basename.c",
34+
"string/index.c",
35+
"string/memccpy.c",
36+
"string/memchr.c",
37+
"string/memcmp.c",
38+
"string/memcpy.c",
39+
"string/memmem.c",
40+
"string/memmove.c",
41+
"string/mempcpy.c",
42+
"string/memrchr.c",
43+
"string/memset.c",
44+
"string/rawmemchr.c",
45+
"string/rindex.c",
46+
"string/stpcpy.c",
47+
"string/stpncpy.c",
48+
"string/strcasecmp.c",
49+
"string/strcasecmp_l.c",
50+
"string/strcasestr.c",
51+
"string/strcat.c",
52+
"string/strchr.c",
53+
"string/strchrnul.c",
54+
"string/strcmp.c",
55+
"string/strcoll.c",
56+
"string/strcoll_l.c",
57+
"string/strcpy.c",
58+
"string/strcspn.c",
59+
"string/strdup.c",
60+
"string/strerror.c",
61+
"string/strerror_r.c",
62+
"string/strlcat.c",
63+
"string/strlcpy.c",
64+
"string/strlen.c",
65+
"string/strlwr.c",
66+
"string/strncasecmp.c",
67+
"string/strncasecmp_l.c",
68+
"string/strncat.c",
69+
"string/strncmp.c",
70+
"string/strncpy.c",
71+
"string/strndup.c",
72+
"string/strnlen.c",
73+
"string/strnstr.c",
74+
"string/strpbrk.c",
75+
"string/strrchr.c",
76+
"string/strsep.c",
77+
"string/strsignal.c",
78+
"string/strspn.c",
79+
"string/strstr.c",
80+
"string/strtok.c",
81+
"string/strtok_r.c",
82+
"string/strupr.c",
83+
"string/strverscmp.c",
84+
"string/strxfrm.c",
85+
"string/strxfrm_l.c",
86+
"string/swab.c",
87+
"string/timingsafe_bcmp.c",
88+
"string/timingsafe_memcmp.c",
89+
"string/u_strerr.c",
90+
"string/wcpcpy.c",
91+
"string/wcpncpy.c",
92+
"string/wcscasecmp.c",
93+
"string/wcscasecmp_l.c",
94+
"string/wcscat.c",
95+
"string/wcschr.c",
96+
"string/wcscmp.c",
97+
"string/wcscoll.c",
98+
"string/wcscoll_l.c",
99+
"string/wcscpy.c",
100+
"string/wcscspn.c",
101+
"string/wcsdup.c",
102+
"string/wcslcat.c",
103+
"string/wcslcpy.c",
104+
"string/wcslen.c",
105+
"string/wcsncasecmp.c",
106+
"string/wcsncasecmp_l.c",
107+
"string/wcsncat.c",
108+
"string/wcsncmp.c",
109+
"string/wcsncpy.c",
110+
"string/wcsnlen.c",
111+
"string/wcspbrk.c",
112+
"string/wcsrchr.c",
113+
"string/wcsspn.c",
114+
"string/wcsstr.c",
115+
"string/wcstok.c",
116+
"string/wcswidth.c",
117+
"string/wcsxfrm.c",
118+
"string/wcsxfrm_l.c",
119+
"string/wcwidth.c",
120+
"string/wmemchr.c",
121+
"string/wmemcmp.c",
122+
"string/wmemcpy.c",
123+
"string/wmemmove.c",
124+
"string/wmempcpy.c",
125+
"string/wmemset.c",
126+
"string/xpg_strerror_r.c",
127+
}

compileopts/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package compileopts
55
import (
66
"errors"
77
"fmt"
8+
"path/filepath"
89
"regexp"
910
"strconv"
1011
"strings"
@@ -125,6 +126,11 @@ func (c *Config) CFlags() []string {
125126
for _, flag := range c.Target.CFlags {
126127
cflags = append(cflags, strings.Replace(flag, "{root}", goenv.Get("TINYGOROOT"), -1))
127128
}
129+
if c.Target.Libc == "picolibc" {
130+
root := goenv.Get("TINYGOROOT")
131+
cflags = append(cflags, "--sysroot="+filepath.Join(root, "lib", "picolibc", "newlib", "libc"))
132+
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
133+
}
128134
return cflags
129135
}
130136

compileopts/target.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type TargetSpec struct {
3232
Compiler string `json:"compiler"`
3333
Linker string `json:"linker"`
3434
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
35+
Libc string `json:"libc"`
3536
CFlags []string `json:"cflags"`
3637
LDFlags []string `json:"ldflags"`
3738
LinkerScript string `json:"linkerscript"`
@@ -84,6 +85,9 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
8485
if spec2.RTLib != "" {
8586
spec.RTLib = spec2.RTLib
8687
}
88+
if spec2.Libc != "" {
89+
spec.Libc = spec2.Libc
90+
}
8791
spec.CFlags = append(spec.CFlags, spec2.CFlags...)
8892
spec.LDFlags = append(spec.LDFlags, spec2.LDFlags...)
8993
if spec2.LinkerScript != "" {

lib/picolibc

Submodule picolibc added at 80528c6

lib/picolibc-include/picolibc.h

Whitespace-only changes.

main.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ func main() {
777777
}
778778
err := Build(pkgName, *outpath, options)
779779
handleCompilerError(err)
780-
case "build-builtins":
780+
case "build-library":
781781
// Note: this command is only meant to be used while making a release!
782782
if *outpath == "" {
783783
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
@@ -787,7 +787,22 @@ func main() {
787787
if *target == "" {
788788
fmt.Fprintln(os.Stderr, "No target (-target).")
789789
}
790-
path, err := builder.CompilerRT.Load(*target)
790+
if flag.NArg() != 1 {
791+
fmt.Fprintf(os.Stderr, "Build-library only accepts exactly one library name as argument, %d given\n", flag.NArg())
792+
usage()
793+
os.Exit(1)
794+
}
795+
var lib *builder.Library
796+
switch name := flag.Arg(0); name {
797+
case "compiler-rt":
798+
lib = &builder.CompilerRT
799+
case "picolibc":
800+
lib = &builder.Picolibc
801+
default:
802+
fmt.Fprintf(os.Stderr, "Unknown library: %s\n", name)
803+
os.Exit(1)
804+
}
805+
path, err := lib.Load(*target)
791806
handleCompilerError(err)
792807
copyFile(path, *outpath)
793808
case "flash", "gdb":

src/runtime/runtime_arm7tdmi.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,3 @@ func abort() {
7676
for {
7777
}
7878
}
79-
80-
// Implement memset for LLVM and compiler-rt.
81-
//go:export memset
82-
func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) {
83-
for i := uintptr(0); i < size; i++ {
84-
*(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = c
85-
}
86-
}
87-
88-
// Implement memmove for LLVM and compiler-rt.
89-
//go:export memmove
90-
func libc_memmove(dst, src unsafe.Pointer, size uintptr) {
91-
memmove(dst, src, size)
92-
}

0 commit comments

Comments
 (0)