mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 11:07:46 +00:00
922ba6a4a3
This adds support for the 'go install' case, where we link against the
system LLVM (Homebrew, Linux distro version, etc). This does not have an
effect on `make`, which still uses LLVM 19 for now.
The main reason for doing this is because newer distros like Fedora 42
and Homebrew have switched to LLVM 20, so switching to this newer
version helps those people. (I'm one of those people, I'm on Fedora 42).
There are two small changes for WebAssembly included:
* nontrapping-fptoint was enabled in the wasmbuiltin library used for
wasm-unknown. This matches wasm-unknown which already had this
enabled, so it doesn't add any new instructions.
* bulk-memory was enabled in wasi-libc. This was previously enabled in
all the other WebAssembly targets (wasm, wasip1, wasip2) so this
does't add any new instructions. I think it was also enabled in the
wasi-libc build before
https://github.com/tinygo-org/tinygo/pull/4820 but I don't know for
sure.
280 lines
9.8 KiB
Go
280 lines
9.8 KiB
Go
package builder
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/tinygo-org/tinygo/goenv"
|
|
)
|
|
|
|
var libWasiLibc = Library{
|
|
name: "wasi-libc",
|
|
makeHeaders: func(target, includeDir string) error {
|
|
bits := filepath.Join(includeDir, "bits")
|
|
err := os.Mkdir(bits, 0777)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
muslDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib", "wasi-libc/libc-top-half/musl")
|
|
err = buildMuslAllTypes("wasm32", muslDir, bits)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// See MUSL_OMIT_HEADERS in the Makefile.
|
|
omitHeaders := map[string]struct{}{
|
|
"syslog.h": {},
|
|
"wait.h": {},
|
|
"ucontext.h": {},
|
|
"paths.h": {},
|
|
"utmp.h": {},
|
|
"utmpx.h": {},
|
|
"lastlog.h": {},
|
|
"elf.h": {},
|
|
"link.h": {},
|
|
"pwd.h": {},
|
|
"shadow.h": {},
|
|
"grp.h": {},
|
|
"mntent.h": {},
|
|
"netdb.h": {},
|
|
"resolv.h": {},
|
|
"pty.h": {},
|
|
"dlfcn.h": {},
|
|
"setjmp.h": {},
|
|
"ulimit.h": {},
|
|
"wordexp.h": {},
|
|
"spawn.h": {},
|
|
"termios.h": {},
|
|
"libintl.h": {},
|
|
"aio.h": {},
|
|
|
|
"stdarg.h": {},
|
|
"stddef.h": {},
|
|
|
|
"pthread.h": {},
|
|
}
|
|
|
|
for _, glob := range [][2]string{
|
|
{"libc-bottom-half/headers/public/*.h", ""},
|
|
{"libc-bottom-half/headers/public/wasi/*.h", "wasi"},
|
|
{"libc-top-half/musl/arch/wasm32/bits/*.h", "bits"},
|
|
{"libc-top-half/musl/include/*.h", ""},
|
|
{"libc-top-half/musl/include/netinet/*.h", "netinet"},
|
|
{"libc-top-half/musl/include/sys/*.h", "sys"},
|
|
} {
|
|
matches, _ := filepath.Glob(filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc", glob[0]))
|
|
outDir := filepath.Join(includeDir, glob[1])
|
|
os.MkdirAll(outDir, 0o777)
|
|
for _, match := range matches {
|
|
name := filepath.Base(match)
|
|
if _, ok := omitHeaders[name]; ok {
|
|
continue
|
|
}
|
|
data, err := os.ReadFile(match)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = os.WriteFile(filepath.Join(outDir, name), data, 0o666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
cflags: func(target, headerPath string) []string {
|
|
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
|
|
return []string{
|
|
"-Werror",
|
|
"-Wall",
|
|
"-std=gnu11",
|
|
"-nostdlibinc",
|
|
"-mnontrapping-fptoint", "-msign-ext", "-mbulk-memory",
|
|
"-Wno-null-pointer-arithmetic", "-Wno-unused-parameter", "-Wno-sign-compare", "-Wno-unused-variable", "-Wno-unused-function", "-Wno-ignored-attributes", "-Wno-missing-braces", "-Wno-ignored-pragmas", "-Wno-unused-but-set-variable", "-Wno-unknown-warning-option",
|
|
"-Wno-parentheses", "-Wno-shift-op-parentheses", "-Wno-bitwise-op-parentheses", "-Wno-logical-op-parentheses", "-Wno-string-plus-int", "-Wno-dangling-else", "-Wno-unknown-pragmas",
|
|
"-DNDEBUG",
|
|
"-D__wasilibc_printscan_no_long_double",
|
|
"-D__wasilibc_printscan_full_support_option=\"long double support is disabled\"",
|
|
"-DBULK_MEMORY_THRESHOLD=32", // default threshold in wasi-libc
|
|
"-isystem", headerPath,
|
|
"-I" + libcDir + "/libc-top-half/musl/src/include",
|
|
"-I" + libcDir + "/libc-top-half/musl/src/internal",
|
|
"-I" + libcDir + "/libc-top-half/musl/arch/wasm32",
|
|
"-I" + libcDir + "/libc-top-half/musl/arch/generic",
|
|
"-I" + libcDir + "/libc-top-half/headers/private",
|
|
}
|
|
},
|
|
cflagsForFile: func(path string) []string {
|
|
if strings.HasPrefix(path, "libc-bottom-half"+string(os.PathSeparator)) {
|
|
libcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc")
|
|
return []string{
|
|
"-I" + libcDir + "/libc-bottom-half/headers/private",
|
|
"-I" + libcDir + "/libc-bottom-half/cloudlibc/src/include",
|
|
"-I" + libcDir + "/libc-bottom-half/cloudlibc/src",
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
|
librarySources: func(target string) ([]string, error) {
|
|
type filePattern struct {
|
|
glob string
|
|
exclude []string
|
|
}
|
|
|
|
// See: LIBC_TOP_HALF_MUSL_SOURCES in the Makefile
|
|
globs := []filePattern{
|
|
// Top half: mostly musl sources.
|
|
{glob: "libc-top-half/sources/*.c"},
|
|
{glob: "libc-top-half/musl/src/conf/*.c"},
|
|
{glob: "libc-top-half/musl/src/internal/*.c", exclude: []string{
|
|
"procfdname.c", "syscall.c", "syscall_ret.c", "vdso.c", "version.c",
|
|
}},
|
|
{glob: "libc-top-half/musl/src/locale/*.c", exclude: []string{
|
|
"dcngettext.c", "textdomain.c", "bind_textdomain_codeset.c"}},
|
|
{glob: "libc-top-half/musl/src/math/*.c", exclude: []string{
|
|
"__signbit.c", "__signbitf.c", "__signbitl.c",
|
|
"__fpclassify.c", "__fpclassifyf.c", "__fpclassifyl.c",
|
|
"ceilf.c", "ceil.c",
|
|
"floorf.c", "floor.c",
|
|
"truncf.c", "trunc.c",
|
|
"rintf.c", "rint.c",
|
|
"nearbyintf.c", "nearbyint.c",
|
|
"sqrtf.c", "sqrt.c",
|
|
"fabsf.c", "fabs.c",
|
|
"copysignf.c", "copysign.c",
|
|
"fminf.c", "fmaxf.c",
|
|
"fmin.c", "fmax.c,",
|
|
}},
|
|
{glob: "libc-top-half/musl/src/multibyte/*.c"},
|
|
{glob: "libc-top-half/musl/src/stdio/*.c", exclude: []string{
|
|
"vfwscanf.c", "vfwprintf.c", // long double is unsupported
|
|
"__lockfile.c", "flockfile.c", "funlockfile.c", "ftrylockfile.c",
|
|
"rename.c",
|
|
"tmpnam.c", "tmpfile.c", "tempnam.c",
|
|
"popen.c", "pclose.c",
|
|
"remove.c",
|
|
"gets.c"}},
|
|
{glob: "libc-top-half/musl/src/stdlib/*.c"},
|
|
{glob: "libc-top-half/musl/src/string/*.c", exclude: []string{
|
|
"strsignal.c"}},
|
|
|
|
// Bottom half: connect top half to WASI equivalents.
|
|
{glob: "libc-bottom-half/cloudlibc/src/libc/*/*.c"},
|
|
{glob: "libc-bottom-half/cloudlibc/src/libc/sys/*/*.c"},
|
|
{glob: "libc-bottom-half/sources/*.c"},
|
|
}
|
|
|
|
// See: LIBC_TOP_HALF_MUSL_SOURCES in the Makefile
|
|
sources := []string{
|
|
"libc-top-half/musl/src/misc/a64l.c",
|
|
"libc-top-half/musl/src/misc/basename.c",
|
|
"libc-top-half/musl/src/misc/dirname.c",
|
|
"libc-top-half/musl/src/misc/ffs.c",
|
|
"libc-top-half/musl/src/misc/ffsl.c",
|
|
"libc-top-half/musl/src/misc/ffsll.c",
|
|
"libc-top-half/musl/src/misc/fmtmsg.c",
|
|
"libc-top-half/musl/src/misc/getdomainname.c",
|
|
"libc-top-half/musl/src/misc/gethostid.c",
|
|
"libc-top-half/musl/src/misc/getopt.c",
|
|
"libc-top-half/musl/src/misc/getopt_long.c",
|
|
"libc-top-half/musl/src/misc/getsubopt.c",
|
|
"libc-top-half/musl/src/misc/uname.c",
|
|
"libc-top-half/musl/src/misc/nftw.c",
|
|
"libc-top-half/musl/src/errno/strerror.c",
|
|
"libc-top-half/musl/src/network/htonl.c",
|
|
"libc-top-half/musl/src/network/htons.c",
|
|
"libc-top-half/musl/src/network/ntohl.c",
|
|
"libc-top-half/musl/src/network/ntohs.c",
|
|
"libc-top-half/musl/src/network/inet_ntop.c",
|
|
"libc-top-half/musl/src/network/inet_pton.c",
|
|
"libc-top-half/musl/src/network/inet_aton.c",
|
|
"libc-top-half/musl/src/network/in6addr_any.c",
|
|
"libc-top-half/musl/src/network/in6addr_loopback.c",
|
|
"libc-top-half/musl/src/fenv/fenv.c",
|
|
"libc-top-half/musl/src/fenv/fesetround.c",
|
|
"libc-top-half/musl/src/fenv/feupdateenv.c",
|
|
"libc-top-half/musl/src/fenv/fesetexceptflag.c",
|
|
"libc-top-half/musl/src/fenv/fegetexceptflag.c",
|
|
"libc-top-half/musl/src/fenv/feholdexcept.c",
|
|
"libc-top-half/musl/src/exit/exit.c",
|
|
"libc-top-half/musl/src/exit/atexit.c",
|
|
"libc-top-half/musl/src/exit/assert.c",
|
|
"libc-top-half/musl/src/exit/quick_exit.c",
|
|
"libc-top-half/musl/src/exit/at_quick_exit.c",
|
|
"libc-top-half/musl/src/time/strftime.c",
|
|
"libc-top-half/musl/src/time/asctime.c",
|
|
"libc-top-half/musl/src/time/asctime_r.c",
|
|
"libc-top-half/musl/src/time/ctime.c",
|
|
"libc-top-half/musl/src/time/ctime_r.c",
|
|
"libc-top-half/musl/src/time/wcsftime.c",
|
|
"libc-top-half/musl/src/time/strptime.c",
|
|
"libc-top-half/musl/src/time/difftime.c",
|
|
"libc-top-half/musl/src/time/timegm.c",
|
|
"libc-top-half/musl/src/time/ftime.c",
|
|
"libc-top-half/musl/src/time/gmtime.c",
|
|
"libc-top-half/musl/src/time/gmtime_r.c",
|
|
"libc-top-half/musl/src/time/timespec_get.c",
|
|
"libc-top-half/musl/src/time/getdate.c",
|
|
"libc-top-half/musl/src/time/localtime.c",
|
|
"libc-top-half/musl/src/time/localtime_r.c",
|
|
"libc-top-half/musl/src/time/mktime.c",
|
|
"libc-top-half/musl/src/time/__tm_to_secs.c",
|
|
"libc-top-half/musl/src/time/__month_to_secs.c",
|
|
"libc-top-half/musl/src/time/__secs_to_tm.c",
|
|
"libc-top-half/musl/src/time/__year_to_secs.c",
|
|
"libc-top-half/musl/src/time/__tz.c",
|
|
"libc-top-half/musl/src/fcntl/creat.c",
|
|
"libc-top-half/musl/src/dirent/alphasort.c",
|
|
"libc-top-half/musl/src/dirent/versionsort.c",
|
|
"libc-top-half/musl/src/env/__stack_chk_fail.c",
|
|
"libc-top-half/musl/src/env/clearenv.c",
|
|
"libc-top-half/musl/src/env/getenv.c",
|
|
"libc-top-half/musl/src/env/putenv.c",
|
|
"libc-top-half/musl/src/env/setenv.c",
|
|
"libc-top-half/musl/src/env/unsetenv.c",
|
|
"libc-top-half/musl/src/unistd/posix_close.c",
|
|
"libc-top-half/musl/src/stat/futimesat.c",
|
|
"libc-top-half/musl/src/legacy/getpagesize.c",
|
|
"libc-top-half/musl/src/thread/thrd_sleep.c",
|
|
}
|
|
|
|
basepath := goenv.Get("TINYGOROOT") + "/lib/wasi-libc/"
|
|
for _, pattern := range globs {
|
|
matches, err := filepath.Glob(basepath + pattern.glob)
|
|
if err != nil {
|
|
// From the documentation:
|
|
// > Glob ignores file system errors such as I/O errors reading
|
|
// > directories. The only possible returned error is
|
|
// > ErrBadPattern, when pattern is malformed.
|
|
// So the only possible error is when the (statically defined)
|
|
// pattern is wrong. In other words, a programming bug.
|
|
return nil, fmt.Errorf("wasi-libc: could not glob source dirs: %w", err)
|
|
}
|
|
if len(matches) == 0 {
|
|
return nil, fmt.Errorf("wasi-libc: did not find any files for pattern %#v", pattern)
|
|
}
|
|
excludeSet := map[string]struct{}{}
|
|
for _, exclude := range pattern.exclude {
|
|
excludeSet[exclude] = struct{}{}
|
|
}
|
|
for _, match := range matches {
|
|
if _, ok := excludeSet[filepath.Base(match)]; ok {
|
|
continue
|
|
}
|
|
relpath, err := filepath.Rel(basepath, match)
|
|
if err != nil {
|
|
// Not sure if this is even possible.
|
|
return nil, err
|
|
}
|
|
sources = append(sources, relpath)
|
|
}
|
|
}
|
|
return sources, nil
|
|
},
|
|
}
|