
The main change is in building the libraries, where -fshort-enums was passed on RISC-V while other C files weren't compiled with this setting. Note: the test already passed before this change, but it seems like a good idea to explicitly test for enum size consistency. There is also not a particular reason not to pass -fshort-enums on RISC-V. Perhaps it's better to do it there too (on baremetal targets that don't have to worry about binary compatibility).
102 строки
3,1 КиБ
Go
102 строки
3,1 КиБ
Go
package builder
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/tinygo-org/tinygo/goenv"
|
|
)
|
|
|
|
// Library is a container for information about a single C library, such as a
|
|
// compiler runtime or libc.
|
|
type Library struct {
|
|
// The library name, such as compiler-rt or picolibc.
|
|
name string
|
|
|
|
cflags func() []string
|
|
|
|
// The source directory, relative to TINYGOROOT.
|
|
sourceDir string
|
|
|
|
// The source files, relative to sourceDir.
|
|
sources func(target string) []string
|
|
}
|
|
|
|
// fullPath returns the full path to the source directory.
|
|
func (l *Library) fullPath() string {
|
|
return filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir)
|
|
}
|
|
|
|
// sourcePaths returns a slice with the full paths to the source files.
|
|
func (l *Library) sourcePaths(target string) []string {
|
|
sources := l.sources(target)
|
|
paths := make([]string, len(sources))
|
|
for i, name := range sources {
|
|
paths[i] = filepath.Join(l.fullPath(), name)
|
|
}
|
|
return paths
|
|
}
|
|
|
|
// Load the library archive, possibly generating and caching it if needed.
|
|
func (l *Library) Load(target string) (path string, err error) {
|
|
// Try to load a precompiled library.
|
|
precompiledPath := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", target, l.name+".a")
|
|
if _, err := os.Stat(precompiledPath); err == nil {
|
|
// Found a precompiled library for this OS/architecture. Return the path
|
|
// directly.
|
|
return precompiledPath, nil
|
|
}
|
|
|
|
outfile := l.name + "-" + target + ".a"
|
|
|
|
// Try to fetch this library from the cache.
|
|
if path, err := cacheLoad(outfile, commands["clang"][0], l.sourcePaths(target)); path != "" || err != nil {
|
|
// Cache hit.
|
|
return path, err
|
|
}
|
|
// Cache miss, build it now.
|
|
|
|
dirPrefix := "tinygo-" + l.name
|
|
remapDir := filepath.Join(os.TempDir(), dirPrefix)
|
|
dir, err := ioutil.TempDir(os.TempDir(), dirPrefix)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
// Precalculate the flags to the compiler invocation.
|
|
args := append(l.cflags(), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
|
|
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
|
args = append(args, "-fshort-enums")
|
|
}
|
|
if strings.HasPrefix(target, "riscv32-") {
|
|
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
|
}
|
|
|
|
// Compile all sources.
|
|
var objs []string
|
|
for _, srcpath := range l.sourcePaths(target) {
|
|
objpath := filepath.Join(dir, filepath.Base(srcpath)+".o")
|
|
objs = append(objs, objpath)
|
|
// Note: -fdebug-prefix-map is necessary to make the output archive
|
|
// reproducible. Otherwise the temporary directory is stored in the
|
|
// archive itself, which varies each run.
|
|
err := runCCompiler("clang", append(args, "-o", objpath, srcpath)...)
|
|
if err != nil {
|
|
return "", &commandError{"failed to build", srcpath, err}
|
|
}
|
|
}
|
|
|
|
// Put all the object files in a single archive. This archive file will be
|
|
// used to statically link this library.
|
|
arpath := filepath.Join(dir, l.name+".a")
|
|
err = makeArchive(arpath, objs)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Store this archive in the cache.
|
|
return cacheStore(arpath, outfile, commands["clang"][0], l.sourcePaths(target))
|
|
}
|