Skip to content
Permalink
Browse files

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.
  • Loading branch information...
aykevl committed Jan 25, 2019
1 parent 5b50759 commit 9bbb233cf02be8f0521bfbc6f96f70c8a0c5c6b8
Showing with 109 additions and 32 deletions.
  1. +6 −0 Makefile
  2. +36 −20 buildcache.go
  3. +50 −8 builtins.go
  4. +17 −4 main.go
@@ -117,6 +117,9 @@ release: static gen-device
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
@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 -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/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 src build/release/tinygo/src
@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

# Binary that can run on the host.
@@ -80,29 +80,45 @@ func cacheStore(tmppath, name, configKey string, sourceFiles []string) (string,
return "", err
}
cachepath := filepath.Join(dir, name)
err = os.Rename(tmppath, cachepath)
err = moveFile(tmppath, cachepath)
if err != nil {
inf, err := os.Open(tmppath)
if err != nil {
return "", err
}
defer inf.Close()
outf, err := os.Create(cachepath + ".tmp")
if err != nil {
return "", err
}
return "", err
}
return cachepath, nil
}

_, err = io.Copy(outf, inf)
if err != nil {
return "", err
}
// 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 = os.Rename(cachepath+".tmp", cachepath)
if err != nil {
return "", err
}
_, err = io.Copy(outf, inf)
if err != nil {
os.Remove(outpath)
return err
}

return cachepath, outf.Close()
err = os.Rename(dst+".tmp", dst)
if err != nil {
return err
}
return cachepath, nil

return outf.Close()
}
@@ -157,16 +157,29 @@ var aeabiBuiltins = []string{

func builtinFiles(target string) []string {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
if target[:3] == "arm" {
if strings.HasPrefix(target, "arm") {
builtins = append(builtins, aeabiBuiltins...)
}
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.
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"
builtinsDir := filepath.Join(sourceDir(), "lib", "compiler-rt", "lib", "builtins")
builtinsDir := builtinsDir()

builtins := builtinFiles(target)
srcs := make([]string, len(builtins))
@@ -178,9 +191,33 @@ func loadBuiltins(target string) (path string, err error) {
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 {
return "", err
return err
}
defer os.RemoveAll(dir)

@@ -195,13 +232,16 @@ func loadBuiltins(target string) (path string, err error) {
objpath := filepath.Join(dir, objname+".o")
objs = append(objs, objpath)
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.Stderr = os.Stderr
cmd.Dir = dir
err = cmd.Run()
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
err = cmd.Run()
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,21 +186,20 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act

// Load builtins library from the cache, possibly compiling it on the
// fly.
var cachePath string
var librt string
if spec.RTLib == "compiler-rt" {
librt, err := loadBuiltins(spec.Triple)
librt, err = loadBuiltins(spec.Triple)
if err != nil {
return err
}
cachePath, _ = filepath.Split(librt)
}

// Prepare link command.
executable := filepath.Join(dir, "main")
tmppath := executable // final file
ldflags := append(spec.LDFlags, "-o", executable, objfile)
if spec.RTLib == "compiler-rt" {
ldflags = append(ldflags, "-L", cachePath, "-lrt-"+spec.Triple)
ldflags = append(ldflags, librt)
}

// Compile extra files.
@@ -554,6 +553,20 @@ func main() {
}
err := Build(flag.Arg(0), *outpath, target, config)
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":
if *outpath != "" {
fmt.Fprintln(os.Stderr, "Output cannot be specified with the flash command.")

0 comments on commit 9bbb233

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.