mirror of https://github.com/tinygo-org/tinygo.git
wasmstm32webassemblymicrocontrollerarmavrspiwasiadafruitarduinocircuitplayground-expressgpioi2cllvmmicrobitnrf51nrf52nrf52840samd21tinygo
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.2 KiB
102 lines
3.2 KiB
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", "-fomit-frame-pointer", "-mfloat-abi=soft")
|
|
}
|
|
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))
|
|
}
|
|
|