cgo: add support for stdio in picolibc and wasi-libc
This adds support for stdio in picolibc and fixes wasm_exec.js so that it can also support C puts. With this, C stdout works on all supported platforms.
Этот коммит содержится в:
родитель
1645f45c1a
коммит
14bb90c3c0
11 изменённых файлов: 158 добавлений и 7 удалений
|
@ -15,7 +15,7 @@ RUN cd /tinygo/ && \
|
|||
git submodule sync && \
|
||||
git submodule update --init --recursive --force
|
||||
|
||||
COPY ./lib/picolibc-include/* /tinygo/lib/picolibc-include/
|
||||
COPY ./lib/picolibc-* /tinygo/lib/
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
go install /tinygo/
|
||||
|
|
3
Makefile
3
Makefile
|
@ -480,6 +480,7 @@ build/release: tinygo gen-device wasi-libc
|
|||
@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/picolibc/newlib/libm
|
||||
@mkdir -p build/release/tinygo/lib/wasi-libc
|
||||
@mkdir -p build/release/tinygo/pkg/armv6m-unknown-unknown-eabi
|
||||
@mkdir -p build/release/tinygo/pkg/armv7m-unknown-unknown-eabi
|
||||
|
@ -498,7 +499,9 @@ build/release: tinygo gen-device wasi-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/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
||||
@cp -rp lib/picolibc-include build/release/tinygo/lib
|
||||
@cp -rp lib/picolibc-stdio.c 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
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -49,7 +50,7 @@ func makeArchive(archivePath string, objs []string) error {
|
|||
// Read the symbols and add them to the symbol table.
|
||||
dbg, err := elf.NewFile(objfile)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to open file %s: %w", objpath, err)
|
||||
}
|
||||
symbols, err := dbg.Symbols()
|
||||
if err != nil {
|
||||
|
@ -61,9 +62,8 @@ func makeArchive(archivePath string, objs []string) error {
|
|||
// Don't include local symbols (STB_LOCAL).
|
||||
continue
|
||||
}
|
||||
if elf.ST_TYPE(symbol.Info) != elf.STT_FUNC {
|
||||
if elf.ST_TYPE(symbol.Info) != elf.STT_FUNC && elf.ST_TYPE(symbol.Info) != elf.STT_OBJECT {
|
||||
// Not a function.
|
||||
// TODO: perhaps globals variables should also be included?
|
||||
continue
|
||||
}
|
||||
// Include in archive.
|
||||
|
|
|
@ -12,7 +12,18 @@ 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", "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include", "-I" + picolibcDir + "/tinystdio", "-I" + goenv.Get("TINYGOROOT") + "/lib/picolibc-include"}
|
||||
return []string{
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
"-std=gnu11",
|
||||
"-D_COMPILING_NEWLIB",
|
||||
"-DHAVE_ALIAS_ATTRIBUTE",
|
||||
"-DTINY_STDIO",
|
||||
"-nostdlibinc",
|
||||
"-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include",
|
||||
"-I" + picolibcDir + "/tinystdio",
|
||||
"-I" + goenv.Get("TINYGOROOT") + "/lib/picolibc-include",
|
||||
}
|
||||
},
|
||||
sourceDir: "lib/picolibc/newlib/libc",
|
||||
sources: func(target string) []string {
|
||||
|
@ -21,6 +32,105 @@ var Picolibc = Library{
|
|||
}
|
||||
|
||||
var picolibcSources = []string{
|
||||
"../../../picolibc-stdio.c",
|
||||
|
||||
"tinystdio/asprintf.c",
|
||||
"tinystdio/atod_engine.c",
|
||||
"tinystdio/atod_ryu.c",
|
||||
"tinystdio/atof_engine.c",
|
||||
"tinystdio/atof_ryu.c",
|
||||
//"tinystdio/atold_engine.c", // have_long_double and not long_double_equals_double
|
||||
"tinystdio/clearerr.c",
|
||||
"tinystdio/compare_exchange.c",
|
||||
"tinystdio/dtoa_data.c",
|
||||
"tinystdio/dtoa_engine.c",
|
||||
"tinystdio/dtoa_ryu.c",
|
||||
"tinystdio/ecvtbuf.c",
|
||||
"tinystdio/ecvt.c",
|
||||
"tinystdio/ecvt_data.c",
|
||||
"tinystdio/ecvtfbuf.c",
|
||||
"tinystdio/ecvtf.c",
|
||||
"tinystdio/ecvtf_data.c",
|
||||
"tinystdio/exchange.c",
|
||||
//"tinystdio/fclose.c", // posix-io
|
||||
"tinystdio/fcvtbuf.c",
|
||||
"tinystdio/fcvt.c",
|
||||
"tinystdio/fcvtfbuf.c",
|
||||
"tinystdio/fcvtf.c",
|
||||
"tinystdio/fdevopen.c",
|
||||
//"tinystdio/fdopen.c", // posix-io
|
||||
"tinystdio/feof.c",
|
||||
"tinystdio/ferror.c",
|
||||
"tinystdio/fflush.c",
|
||||
"tinystdio/fgetc.c",
|
||||
"tinystdio/fgets.c",
|
||||
"tinystdio/fileno.c",
|
||||
"tinystdio/filestrget.c",
|
||||
"tinystdio/filestrputalloc.c",
|
||||
"tinystdio/filestrput.c",
|
||||
//"tinystdio/fopen.c", // posix-io
|
||||
"tinystdio/fprintf.c",
|
||||
"tinystdio/fputc.c",
|
||||
"tinystdio/fputs.c",
|
||||
"tinystdio/fread.c",
|
||||
"tinystdio/fscanf.c",
|
||||
"tinystdio/fseek.c",
|
||||
"tinystdio/ftell.c",
|
||||
"tinystdio/ftoa_data.c",
|
||||
"tinystdio/ftoa_engine.c",
|
||||
"tinystdio/ftoa_ryu.c",
|
||||
"tinystdio/fwrite.c",
|
||||
"tinystdio/gcvtbuf.c",
|
||||
"tinystdio/gcvt.c",
|
||||
"tinystdio/gcvtfbuf.c",
|
||||
"tinystdio/gcvtf.c",
|
||||
"tinystdio/getchar.c",
|
||||
"tinystdio/gets.c",
|
||||
"tinystdio/matchcaseprefix.c",
|
||||
"tinystdio/perror.c",
|
||||
//"tinystdio/posixiob.c", // posix-io
|
||||
//"tinystdio/posixio.c", // posix-io
|
||||
"tinystdio/printf.c",
|
||||
"tinystdio/putchar.c",
|
||||
"tinystdio/puts.c",
|
||||
"tinystdio/ryu_divpow2.c",
|
||||
"tinystdio/ryu_log10.c",
|
||||
"tinystdio/ryu_log2pow5.c",
|
||||
"tinystdio/ryu_pow5bits.c",
|
||||
"tinystdio/ryu_table.c",
|
||||
"tinystdio/ryu_umul128.c",
|
||||
"tinystdio/scanf.c",
|
||||
"tinystdio/setbuf.c",
|
||||
"tinystdio/setvbuf.c",
|
||||
//"tinystdio/sflags.c", // posix-io
|
||||
"tinystdio/snprintf.c",
|
||||
"tinystdio/snprintfd.c",
|
||||
"tinystdio/snprintff.c",
|
||||
"tinystdio/sprintf.c",
|
||||
"tinystdio/sprintfd.c",
|
||||
"tinystdio/sprintff.c",
|
||||
"tinystdio/sscanf.c",
|
||||
"tinystdio/strfromd.c",
|
||||
"tinystdio/strfromf.c",
|
||||
"tinystdio/strtod.c",
|
||||
"tinystdio/strtod_l.c",
|
||||
"tinystdio/strtof.c",
|
||||
//"tinystdio/strtold.c", // have_long_double and not long_double_equals_double
|
||||
//"tinystdio/strtold_l.c", // have_long_double and not long_double_equals_double
|
||||
"tinystdio/ungetc.c",
|
||||
"tinystdio/vasprintf.c",
|
||||
"tinystdio/vfiprintf.c",
|
||||
"tinystdio/vfiscanf.c",
|
||||
"tinystdio/vfprintf.c",
|
||||
"tinystdio/vfprintff.c",
|
||||
"tinystdio/vfscanf.c",
|
||||
"tinystdio/vfscanff.c",
|
||||
"tinystdio/vprintf.c",
|
||||
"tinystdio/vscanf.c",
|
||||
"tinystdio/vsnprintf.c",
|
||||
"tinystdio/vsprintf.c",
|
||||
"tinystdio/vsscanf.c",
|
||||
|
||||
"string/bcmp.c",
|
||||
"string/bcopy.c",
|
||||
"string/bzero.c",
|
||||
|
|
|
@ -206,7 +206,12 @@ func (c *Config) CFlags() []string {
|
|||
}
|
||||
if c.Target.Libc == "picolibc" {
|
||||
root := goenv.Get("TINYGOROOT")
|
||||
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
|
||||
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
|
||||
cflags = append(cflags,
|
||||
"-nostdlibinc",
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"),
|
||||
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"),
|
||||
)
|
||||
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
|
||||
}
|
||||
// Always emit debug information. It is optionally stripped at link time.
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 80528c684b10aaee977397e7eb40c4784e6dc433
|
||||
Subproject commit f68b8204f797d6b3bfbc7c4da4d257961fbc8770
|
18
lib/picolibc-stdio.c
Обычный файл
18
lib/picolibc-stdio.c
Обычный файл
|
@ -0,0 +1,18 @@
|
|||
// This file is included in the picolibc build.
|
||||
// It makes stdio functions available to the C library.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
// Defined in the runtime package. Writes to the default console (usually, the
|
||||
// first UART or an USB-CDC device).
|
||||
int runtime_putchar(char, FILE*);
|
||||
|
||||
// Define stdin, stdout, and stderr as a single object.
|
||||
// This object must not reside in ROM.
|
||||
static FILE __stdio = FDEV_SETUP_STREAM(runtime_putchar, NULL, NULL, _FDEV_SETUP_WRITE);
|
||||
|
||||
// Define the underlying structs for stdin, stdout, and stderr.
|
||||
FILE *const stdin = &__stdio;
|
||||
__strong_reference(stdin, stdout);
|
||||
__strong_reference(stdin, stderr);
|
|
@ -46,6 +46,11 @@ func libc_free(ptr unsafe.Pointer) {
|
|||
free(ptr)
|
||||
}
|
||||
|
||||
//export runtime_putchar
|
||||
func runtime_putchar(c byte) {
|
||||
putchar(c)
|
||||
}
|
||||
|
||||
//go:linkname syscall_Exit syscall.Exit
|
||||
func syscall_Exit(code int) {
|
||||
exit(code)
|
||||
|
|
|
@ -256,6 +256,7 @@
|
|||
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
|
||||
let ptr = mem().getUint32(iov_ptr + 0, true);
|
||||
let len = mem().getUint32(iov_ptr + 4, true);
|
||||
nwritten += len;
|
||||
for (let i=0; i<len; i++) {
|
||||
let c = mem().getUint8(ptr+i);
|
||||
if (c == 13) { // CR
|
||||
|
@ -276,6 +277,9 @@
|
|||
mem().setUint32(nwritten_ptr, nwritten, true);
|
||||
return 0;
|
||||
},
|
||||
fd_close: () => 0, // dummy
|
||||
fd_fdstat_get: () => 0, // dummy
|
||||
fd_seek: () => 0, // dummy
|
||||
"proc_exit": (code) => {
|
||||
if (global.process) {
|
||||
// Node.js
|
||||
|
|
5
testdata/cgo/main.go
предоставленный
5
testdata/cgo/main.go
предоставленный
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
#include <stdio.h>
|
||||
int fortytwo(void);
|
||||
#include "main.h"
|
||||
int mul(int, int);
|
||||
|
@ -139,6 +140,10 @@ func main() {
|
|||
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])))]))
|
||||
|
||||
// libc: test basic stdio functionality
|
||||
putsBuf := []byte("line written using C puts\x00")
|
||||
C.puts((*C.char)(unsafe.Pointer(&putsBuf[0])))
|
||||
}
|
||||
|
||||
func printUnion(union C.joined_t) C.joined_t {
|
||||
|
|
1
testdata/cgo/out.txt
предоставленный
1
testdata/cgo/out.txt
предоставленный
|
@ -62,3 +62,4 @@ option 3A: 21
|
|||
enum width matches: true
|
||||
CFLAGS value: 17
|
||||
copied string: foobar
|
||||
line written using C puts
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче