Skip to content

Commit e1d6814

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 e1d6814

File tree

18 files changed

+196
-62
lines changed

18 files changed

+196
-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: 13 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,19 @@ 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/ctype build/release/tinygo/lib/picolibc/newlib/libc
297+
@cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc
298+
@cp -rp lib/picolibc/newlib/libc/locale build/release/tinygo/lib/picolibc/newlib/libc
299+
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
300+
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
301+
@cp -rp lib/picolibc-include build/release/tinygo/lib
295302
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
296303
@cp -rp src build/release/tinygo/src
297304
@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
305+
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a compiler-rt
306+
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a compiler-rt
307+
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a compiler-rt
308+
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/picolibc.a picolibc
309+
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/picolibc.a picolibc
310+
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/picolibc.a picolibc
301311
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+
}

cgo/cgo.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
168168
enums: map[string]enumInfo{},
169169
}
170170

171+
// Disable _FORTIFY_SOURCE as it causes problems on macOS.
172+
// Note that it is only disabled for memcpy (etc) calls made from Go, which
173+
// have better alternatives anyway.
174+
cflags = append(cflags, "-D_FORTIFY_SOURCE=0")
175+
171176
// Add a new location for the following file.
172177
generatedTokenPos := p.fset.AddFile(dir+"/!cgo.go", -1, 0)
173178
generatedTokenPos.SetLines([]int{0})

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":

0 commit comments

Comments
 (0)