Skip to content

Commit 6d2fdbb

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 8dba491 commit 6d2fdbb

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
@@ -312,6 +312,7 @@ release: tinygo gen-device wasi-libc
312312
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
313313
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
314314
@mkdir -p build/release/tinygo/lib/nrfx
315+
@mkdir -p build/release/tinygo/lib/picolibc/newlib/libc
315316
@mkdir -p build/release/tinygo/lib/wasi-libc
316317
@mkdir -p build/release/tinygo/pkg/armv6m-none-eabi
317318
@mkdir -p build/release/tinygo/pkg/armv7m-none-eabi
@@ -325,10 +326,19 @@ release: tinygo gen-device wasi-libc
325326
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
326327
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
327328
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
329+
@cp -rp lib/picolibc/newlib/libc/ctype build/release/tinygo/lib/picolibc/newlib/libc
330+
@cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc
331+
@cp -rp lib/picolibc/newlib/libc/locale build/release/tinygo/lib/picolibc/newlib/libc
332+
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
333+
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
334+
@cp -rp lib/picolibc-include build/release/tinygo/lib
328335
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
329336
@cp -rp src build/release/tinygo/src
330337
@cp -rp targets build/release/tinygo/targets
331-
./build/tinygo build-builtins -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a
332-
./build/tinygo build-builtins -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a
333-
./build/tinygo build-builtins -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a
338+
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a compiler-rt
339+
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a compiler-rt
340+
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a compiler-rt
341+
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/picolibc.a picolibc
342+
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/picolibc.a picolibc
343+
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/picolibc.a picolibc
334344
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
@@ -145,6 +145,15 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
145145
ldflags = append(ldflags, librt)
146146
}
147147

148+
// Add libc.
149+
if config.Target.Libc == "picolibc" {
150+
libc, err := Picolibc.Load(config.Triple())
151+
if err != nil {
152+
return err
153+
}
154+
ldflags = append(ldflags, libc)
155+
}
156+
148157
// Compile extra files.
149158
root := goenv.Get("TINYGOROOT")
150159
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
@@ -170,6 +170,11 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
170170
enums: map[string]enumInfo{},
171171
}
172172

173+
// Disable _FORTIFY_SOURCE as it causes problems on macOS.
174+
// Note that it is only disabled for memcpy (etc) calls made from Go, which
175+
// have better alternatives anyway.
176+
cflags = append(cflags, "-D_FORTIFY_SOURCE=0")
177+
173178
// Add a new location for the following file.
174179
generatedTokenPos := p.fset.AddFile(dir+"/!cgo.go", -1, 0)
175180
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"
@@ -163,6 +164,11 @@ func (c *Config) CFlags() []string {
163164
for _, flag := range c.Target.CFlags {
164165
cflags = append(cflags, strings.Replace(flag, "{root}", goenv.Get("TINYGOROOT"), -1))
165166
}
167+
if c.Target.Libc == "picolibc" {
168+
root := goenv.Get("TINYGOROOT")
169+
cflags = append(cflags, "--sysroot="+filepath.Join(root, "lib", "picolibc", "newlib", "libc"))
170+
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
171+
}
166172
return cflags
167173
}
168174

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
@@ -786,7 +786,7 @@ func main() {
786786
}
787787
err := Build(pkgName, *outpath, options)
788788
handleCompilerError(err)
789-
case "build-builtins":
789+
case "build-library":
790790
// Note: this command is only meant to be used while making a release!
791791
if *outpath == "" {
792792
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
@@ -796,7 +796,22 @@ func main() {
796796
if *target == "" {
797797
fmt.Fprintln(os.Stderr, "No target (-target).")
798798
}
799-
path, err := builder.CompilerRT.Load(*target)
799+
if flag.NArg() != 1 {
800+
fmt.Fprintf(os.Stderr, "Build-library only accepts exactly one library name as argument, %d given\n", flag.NArg())
801+
usage()
802+
os.Exit(1)
803+
}
804+
var lib *builder.Library
805+
switch name := flag.Arg(0); name {
806+
case "compiler-rt":
807+
lib = &builder.CompilerRT
808+
case "picolibc":
809+
lib = &builder.Picolibc
810+
default:
811+
fmt.Fprintf(os.Stderr, "Unknown library: %s\n", name)
812+
os.Exit(1)
813+
}
814+
path, err := lib.Load(*target)
800815
handleCompilerError(err)
801816
copyFile(path, *outpath)
802817
case "flash", "gdb":

0 commit comments

Comments
 (0)