main: include prebuilt compiler-rt libraries in release tarball

This avoids depending on clang-7 to build compiler-rt for the most
common ARM microcontrollers.
Этот коммит содержится в:
Ayke van Laethem 2019-01-25 21:36:34 +01:00
родитель 5b507593d2
коммит 9bbb233cf0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
4 изменённых файлов: 111 добавлений и 34 удалений

Просмотреть файл

@ -117,6 +117,9 @@ release: static gen-device
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS @mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/compiler-rt/lib @mkdir -p build/release/tinygo/lib/compiler-rt/lib
@mkdir -p build/release/tinygo/lib/nrfx @mkdir -p build/release/tinygo/lib/nrfx
@mkdir -p build/release/tinygo/pkg/armv6m-none-eabi
@mkdir -p build/release/tinygo/pkg/armv7m-none-eabi
@mkdir -p build/release/tinygo/pkg/armv7em-none-eabi
@cp -p build/tinygo build/release/tinygo/bin @cp -p build/tinygo build/release/tinygo/bin
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS @cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS @cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
@ -126,6 +129,9 @@ release: static gen-device
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx @cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx
@cp -rp src build/release/tinygo/src @cp -rp src build/release/tinygo/src
@cp -rp targets build/release/tinygo/targets @cp -rp targets build/release/tinygo/targets
./build/tinygo build-builtins -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/compiler-rt.a
./build/tinygo build-builtins -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/compiler-rt.a
./build/tinygo build-builtins -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/compiler-rt.a
tar -czf build/release.tar.gz -C build/release tinygo tar -czf build/release.tar.gz -C build/release tinygo
# Binary that can run on the host. # Binary that can run on the host.

Просмотреть файл

@ -80,29 +80,45 @@ func cacheStore(tmppath, name, configKey string, sourceFiles []string) (string,
return "", err return "", err
} }
cachepath := filepath.Join(dir, name) cachepath := filepath.Join(dir, name)
err = os.Rename(tmppath, cachepath) err = moveFile(tmppath, cachepath)
if err != nil { if err != nil {
inf, err := os.Open(tmppath) return "", err
if err != nil {
return "", err
}
defer inf.Close()
outf, err := os.Create(cachepath + ".tmp")
if err != nil {
return "", err
}
_, err = io.Copy(outf, inf)
if err != nil {
return "", err
}
err = os.Rename(cachepath+".tmp", cachepath)
if err != nil {
return "", err
}
return cachepath, outf.Close()
} }
return cachepath, nil return cachepath, nil
} }
// moveFile renames the file from src to dst. If renaming doesn't work (for
// example, the rename crosses a filesystem boundary), the file is copied and
// the old file is removed.
func moveFile(src, dst string) error {
err := os.Rename(src, dst)
if err == nil {
// Success!
return nil
}
// Failed to move, probably a different filesystem.
// Do a copy + remove.
inf, err := os.Open(src)
if err != nil {
return err
}
defer inf.Close()
outpath := dst + ".tmp"
outf, err := os.Create(outpath)
if err != nil {
return err
}
_, err = io.Copy(outf, inf)
if err != nil {
os.Remove(outpath)
return err
}
err = os.Rename(dst+".tmp", dst)
if err != nil {
return err
}
return outf.Close()
}

Просмотреть файл

@ -157,16 +157,29 @@ var aeabiBuiltins = []string{
func builtinFiles(target string) []string { func builtinFiles(target string) []string {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
if target[:3] == "arm" { if strings.HasPrefix(target, "arm") {
builtins = append(builtins, aeabiBuiltins...) builtins = append(builtins, aeabiBuiltins...)
} }
return builtins return builtins
} }
// builtinsDir returns the directory where the sources for compiler-rt are kept.
func builtinsDir() string {
return filepath.Join(sourceDir(), "lib", "compiler-rt", "lib", "builtins")
}
// Get the builtins archive, possibly generating it as needed. // Get the builtins archive, possibly generating it as needed.
func loadBuiltins(target string) (path string, err error) { func loadBuiltins(target string) (path string, err error) {
// Try to load a precompiled compiler-rt library.
precompiledPath := filepath.Join(sourceDir(), "pkg", target, "compiler-rt.a")
if _, err := os.Stat(precompiledPath); err == nil {
// Found a precompiled compiler-rt for this OS/architecture. Return the
// path directly.
return precompiledPath, nil
}
outfile := "librt-" + target + ".a" outfile := "librt-" + target + ".a"
builtinsDir := filepath.Join(sourceDir(), "lib", "compiler-rt", "lib", "builtins") builtinsDir := builtinsDir()
builtins := builtinFiles(target) builtins := builtinFiles(target)
srcs := make([]string, len(builtins)) srcs := make([]string, len(builtins))
@ -178,9 +191,33 @@ func loadBuiltins(target string) (path string, err error) {
return path, err return path, err
} }
dir, err := ioutil.TempDir("", "tinygo-builtins") var cachepath string
err = compileBuiltins(target, func(path string) error {
path, err := cacheStore(path, outfile, commands["clang"], srcs)
cachepath = path
return err
})
return cachepath, err
}
// compileBuiltins compiles builtins from compiler-rt into a static library.
// When it succeeds, it will call the callback with the resulting path. The path
// will be removed after callback returns. If callback returns an error, this is
// passed through to the return value of this function.
func compileBuiltins(target string, callback func(path string) error) error {
builtinsDir := builtinsDir()
builtins := builtinFiles(target)
srcs := make([]string, len(builtins))
for i, name := range builtins {
srcs[i] = filepath.Join(builtinsDir, name)
}
dirPrefix := "tinygo-builtins"
remapDir := filepath.Join(os.TempDir(), dirPrefix)
dir, err := ioutil.TempDir(os.TempDir(), dirPrefix)
if err != nil { if err != nil {
return "", err return err
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
@ -195,13 +232,16 @@ func loadBuiltins(target string) (path string, err error) {
objpath := filepath.Join(dir, objname+".o") objpath := filepath.Join(dir, objname+".o")
objs = append(objs, objpath) objs = append(objs, objpath)
srcpath := filepath.Join(builtinsDir, name) srcpath := filepath.Join(builtinsDir, name)
cmd := exec.Command(commands["clang"], "-c", "-Oz", "-g", "-Werror", "-Wall", "-std=c11", "-fshort-enums", "-nostdlibinc", "-ffunction-sections", "-fdata-sections", "--target="+target, "-o", objpath, srcpath) // 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.
cmd := exec.Command(commands["clang"], "-c", "-Oz", "-g", "-Werror", "-Wall", "-std=c11", "-fshort-enums", "-nostdlibinc", "-ffunction-sections", "-fdata-sections", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir, "-o", objpath, srcpath)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.Dir = dir cmd.Dir = dir
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
return "", &commandError{"failed to build", srcpath, err} return &commandError{"failed to build", srcpath, err}
} }
} }
@ -213,8 +253,10 @@ func loadBuiltins(target string) (path string, err error) {
cmd.Dir = dir cmd.Dir = dir
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
return "", &commandError{"failed to make static library", arpath, err} return &commandError{"failed to make static library", arpath, err}
} }
return cacheStore(arpath, outfile, commands["clang"], srcs) // Give the caller the resulting file. The callback must copy the file,
// because after it returns the temporary directory will be removed.
return callback(arpath)
} }

21
main.go
Просмотреть файл

@ -186,13 +186,12 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
// Load builtins library from the cache, possibly compiling it on the // Load builtins library from the cache, possibly compiling it on the
// fly. // fly.
var cachePath string var librt string
if spec.RTLib == "compiler-rt" { if spec.RTLib == "compiler-rt" {
librt, err := loadBuiltins(spec.Triple) librt, err = loadBuiltins(spec.Triple)
if err != nil { if err != nil {
return err return err
} }
cachePath, _ = filepath.Split(librt)
} }
// Prepare link command. // Prepare link command.
@ -200,7 +199,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
tmppath := executable // final file tmppath := executable // final file
ldflags := append(spec.LDFlags, "-o", executable, objfile) ldflags := append(spec.LDFlags, "-o", executable, objfile)
if spec.RTLib == "compiler-rt" { if spec.RTLib == "compiler-rt" {
ldflags = append(ldflags, "-L", cachePath, "-lrt-"+spec.Triple) ldflags = append(ldflags, librt)
} }
// Compile extra files. // Compile extra files.
@ -554,6 +553,20 @@ func main() {
} }
err := Build(flag.Arg(0), *outpath, target, config) err := Build(flag.Arg(0), *outpath, target, config)
handleCompilerError(err) handleCompilerError(err)
case "build-builtins":
// Note: this command is only meant to be used while making a release!
if *outpath == "" {
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
usage()
os.Exit(1)
}
if *target == "" {
fmt.Fprintln(os.Stderr, "No target (-target).")
}
err := compileBuiltins(*target, func(path string) error {
return moveFile(path, *outpath)
})
handleCompilerError(err)
case "flash", "gdb": case "flash", "gdb":
if *outpath != "" { if *outpath != "" {
fmt.Fprintln(os.Stderr, "Output cannot be specified with the flash command.") fmt.Fprintln(os.Stderr, "Output cannot be specified with the flash command.")