picolibc: add include directory to build artefact

This is really just a preparatory commit for musl support. The idea is
to store not just the archive file (.a) but also an include directory.
This is optional for picolibc but required for musl, so the main purpose
of this commit is the refactor needed for this change.
Этот коммит содержится в:
Ayke van Laethem 2021-09-13 01:16:02 +02:00 коммит произвёл Ron Evans
родитель 39ff13fd1a
коммит 79bdd3f79a
11 изменённых файлов: 176 добавлений и 189 удалений

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

@ -15,8 +15,7 @@ RUN cd /tinygo/ && \
git submodule sync && \ git submodule sync && \
git submodule update --init --recursive --force git submodule update --init --recursive --force
COPY ./lib/picolibc-* /tinygo/lib/ COPY ./lib/picolibc-stdio.c /tinygo/lib/picolibc-stdio.c
COPY ./lib/picolibc-include/* /tinygo/lib/picolibc-include/
RUN cd /tinygo/ && \ RUN cd /tinygo/ && \
go install /tinygo/ go install /tinygo/

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

@ -500,17 +500,16 @@ build/release: tinygo gen-device wasi-libc
@cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc @cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc @cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm @cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
@cp -rp lib/picolibc-include build/release/tinygo/lib
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib @cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot @cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
@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-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/compiler-rt.a compiler-rt ./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/compiler-rt.a compiler-rt ./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/compiler-rt.a compiler-rt ./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/compiler-rt compiler-rt
./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/picolibc.a picolibc ./build/tinygo build-library -target=armv6m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv6m-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/picolibc.a picolibc ./build/tinygo build-library -target=armv7m-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7m-unknown-unknown-eabi/picolibc picolibc
./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/picolibc.a picolibc ./build/tinygo build-library -target=armv7em-unknown-unknown-eabi -o build/release/tinygo/pkg/armv7em-unknown-unknown-eabi/picolibc picolibc
release: build/release release: build/release
tar -czf build/release.tar.gz -C build/release tinygo tar -czf build/release.tar.gz -C build/release tinygo

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

@ -18,17 +18,12 @@ import (
// given as a parameter. It is equivalent to the following command: // given as a parameter. It is equivalent to the following command:
// //
// ar -rcs <archivePath> <objs...> // ar -rcs <archivePath> <objs...>
func makeArchive(archivePath string, objs []string) error { func makeArchive(arfile *os.File, objs []string) error {
// Open the archive file. // Open the archive file.
arfile, err := os.Create(archivePath)
if err != nil {
return err
}
defer arfile.Close()
arwriter := ar.NewWriter(arfile) arwriter := ar.NewWriter(arfile)
err = arwriter.WriteGlobalHeader() err := arwriter.WriteGlobalHeader()
if err != nil { if err != nil {
return &os.PathError{Op: "write ar header", Path: archivePath, Err: err} return &os.PathError{Op: "write ar header", Path: arfile.Name(), Err: err}
} }
// Open all object files and read the symbols for the symbol table. // Open all object files and read the symbols for the symbol table.
@ -133,7 +128,7 @@ func makeArchive(archivePath string, objs []string) error {
return err return err
} }
if int64(int32(offset)) != offset { if int64(int32(offset)) != offset {
return errors.New("large archives (4GB+) not supported: " + archivePath) return errors.New("large archives (4GB+) not supported: " + arfile.Name())
} }
objfiles[i].archiveOffset = int32(offset) objfiles[i].archiveOffset = int32(offset)
@ -160,7 +155,7 @@ func makeArchive(archivePath string, objs []string) error {
return err return err
} }
if n != st.Size() { if n != st.Size() {
return errors.New("file modified during ar creation: " + archivePath) return errors.New("file modified during ar creation: " + arfile.Name())
} }
// File is not needed anymore. // File is not needed anymore.

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

@ -86,6 +86,30 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
// Check for a libc dependency.
// As a side effect, this also creates the headers for the given libc, if
// the libc needs them.
root := goenv.Get("TINYGOROOT")
var libcDependencies []*compileJob
switch config.Target.Libc {
case "picolibc":
libcJob, err := Picolibc.load(config, dir)
if err != nil {
return err
}
libcDependencies = append(libcDependencies, libcJob)
case "wasi-libc":
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
if _, err := os.Stat(path); os.IsNotExist(err) {
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
}
libcDependencies = append(libcDependencies, dummyCompileJob(path))
case "":
// no library specified, so nothing to do
default:
return fmt.Errorf("unknown libc: %s", config.Target.Libc)
}
optLevel, sizeLevel, _ := config.OptLevels() optLevel, sizeLevel, _ := config.OptLevels()
compilerConfig := &compiler.Config{ compilerConfig := &compiler.Config{
Triple: config.Triple(), Triple: config.Triple(),
@ -489,7 +513,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Add compiler-rt dependency if needed. Usually this is a simple load from // Add compiler-rt dependency if needed. Usually this is a simple load from
// a cache. // a cache.
if config.Target.RTLib == "compiler-rt" { if config.Target.RTLib == "compiler-rt" {
job, err := CompilerRT.load(config.Triple(), config.CPU(), dir) job, err := CompilerRT.load(config, dir)
if err != nil { if err != nil {
return err return err
} }
@ -499,7 +523,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Add jobs to compile extra files. These files are in C or assembly and // Add jobs to compile extra files. These files are in C or assembly and
// contain things like the interrupt vector table and low level operations // contain things like the interrupt vector table and low level operations
// such as stack switching. // such as stack switching.
root := goenv.Get("TINYGOROOT")
for _, path := range config.ExtraFiles() { for _, path := range config.ExtraFiles() {
abspath := filepath.Join(root, path) abspath := filepath.Join(root, path)
job := &compileJob{ job := &compileJob{
@ -538,26 +561,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
ldflags = append(ldflags, lprogram.LDFlags...) ldflags = append(ldflags, lprogram.LDFlags...)
} }
// Add libc dependency if needed. // Add libc dependencies, if they exist.
switch config.Target.Libc { linkerDependencies = append(linkerDependencies, libcDependencies...)
case "picolibc":
job, err := Picolibc.load(config.Triple(), config.CPU(), dir)
if err != nil {
return err
}
linkerDependencies = append(linkerDependencies, job)
case "wasi-libc":
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
if _, err := os.Stat(path); os.IsNotExist(err) {
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
}
job := dummyCompileJob(path)
linkerDependencies = append(linkerDependencies, job)
case "":
// no library specified, so nothing to do
default:
return fmt.Errorf("unknown libc: %s", config.Target.Libc)
}
// Strip debug information with -no-debug. // Strip debug information with -no-debug.
if !config.Debug() { if !config.Debug() {

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

@ -1,105 +0,0 @@
package builder
import (
"io"
"os"
"path/filepath"
"time"
"github.com/tinygo-org/tinygo/goenv"
)
// Return the newest timestamp of all the file paths passed in. Used to check
// for stale caches.
func cacheTimestamp(paths []string) (time.Time, error) {
var timestamp time.Time
for _, path := range paths {
st, err := os.Stat(path)
if err != nil {
return time.Time{}, err
}
if timestamp.IsZero() {
timestamp = st.ModTime()
} else if timestamp.Before(st.ModTime()) {
timestamp = st.ModTime()
}
}
return timestamp, nil
}
// Try to load a given file from the cache. Return "", nil if no cached file can
// be found (or the file is stale), return the absolute path if there is a cache
// and return an error on I/O errors.
func cacheLoad(name string, sourceFiles []string) (string, error) {
cachepath := filepath.Join(goenv.Get("GOCACHE"), name)
cacheStat, err := os.Stat(cachepath)
if os.IsNotExist(err) {
return "", nil // does not exist
} else if err != nil {
return "", err // cannot stat cache file
}
sourceTimestamp, err := cacheTimestamp(sourceFiles)
if err != nil {
return "", err // cannot stat source files
}
if cacheStat.ModTime().After(sourceTimestamp) {
return cachepath, nil
} else {
os.Remove(cachepath)
// stale cache
return "", nil
}
}
// Store the file located at tmppath in the cache with the given name. The
// tmppath may or may not be gone afterwards.
func cacheStore(tmppath, name string, sourceFiles []string) (string, error) {
// get the last modified time
if len(sourceFiles) == 0 {
panic("cache: no source files")
}
// TODO: check the config key
dir := goenv.Get("GOCACHE")
err := os.MkdirAll(dir, 0777)
if err != nil {
return "", err
}
cachepath := filepath.Join(dir, name)
err = copyFile(tmppath, cachepath)
if err != nil {
return "", err
}
return cachepath, nil
}
// copyFile copies the given file from src to dst. It can copy over
// a possibly already existing file at the destination.
func copyFile(src, dst string) error {
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 = outf.Close()
if err != nil {
return err
}
return os.Rename(dst+".tmp", dst)
}

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

@ -158,7 +158,9 @@ var aeabiBuiltins = []string{
// For more information, see: https://compiler-rt.llvm.org/ // For more information, see: https://compiler-rt.llvm.org/
var CompilerRT = Library{ var CompilerRT = Library{
name: "compiler-rt", name: "compiler-rt",
cflags: func() []string { return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"} }, cflags: func(headerPath string) []string {
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
},
sourceDir: "lib/compiler-rt/lib/builtins", sourceDir: "lib/compiler-rt/lib/builtins",
sources: func(target string) []string { sources: func(target string) []string {
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins

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

@ -1,10 +1,12 @@
package builder package builder
import ( import (
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
@ -14,7 +16,11 @@ type Library struct {
// The library name, such as compiler-rt or picolibc. // The library name, such as compiler-rt or picolibc.
name string name string
cflags func() []string // makeHeaders creates a header include dir for the library
makeHeaders func(includeDir string) error
// cflags returns the C flags specific to this library
cflags func(headerPath string) []string
// The source directory, relative to TINYGOROOT. // The source directory, relative to TINYGOROOT.
sourceDir string sourceDir string
@ -39,15 +45,15 @@ func (l *Library) sourcePaths(target string) []string {
} }
// Load the library archive, possibly generating and caching it if needed. // Load the library archive, possibly generating and caching it if needed.
// The resulting file is stored in the provided tmpdir, which is expected to be // The resulting directory may be stored in the provided tmpdir, which is
// removed after the Load call. // expected to be removed after the Load call.
func (l *Library) Load(target, tmpdir string) (path string, err error) { func (l *Library) Load(config *compileopts.Config, tmpdir string) (dir string, err error) {
job, err := l.load(target, "", tmpdir) job, err := l.load(config, tmpdir)
if err != nil { if err != nil {
return "", err return "", err
} }
err = runJobs(job) err = runJobs(job)
return job.result, err return filepath.Dir(job.result), err
} }
// load returns a compile job to build this library file for the given target // load returns a compile job to build this library file for the given target
@ -56,29 +62,52 @@ func (l *Library) Load(target, tmpdir string) (path string, err error) {
// been run. // been run.
// The provided tmpdir will be used to store intermediary files and possibly the // The provided tmpdir will be used to store intermediary files and possibly the
// output archive file, it is expected to be removed after use. // output archive file, it is expected to be removed after use.
func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error) { // As a side effect, this call creates the library header files if they didn't
// Try to load a precompiled library. // exist yet.
precompiledPath := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", target, l.name+".a") func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, err error) {
if _, err := os.Stat(precompiledPath); err == nil { outdir, precompiled := config.LibcPath(l.name)
archiveFilePath := filepath.Join(outdir, "lib.a")
if precompiled {
// Found a precompiled library for this OS/architecture. Return the path // Found a precompiled library for this OS/architecture. Return the path
// directly. // directly.
return dummyCompileJob(precompiledPath), nil return dummyCompileJob(archiveFilePath), nil
}
var outfile string
if cpu != "" {
outfile = l.name + "-" + target + "-" + cpu + ".a"
} else {
outfile = l.name + "-" + target + ".a"
} }
// Try to fetch this library from the cache. // Try to fetch this library from the cache.
if path, err := cacheLoad(outfile, l.sourcePaths(target)); path != "" || err != nil { if _, err := os.Stat(archiveFilePath); err == nil {
// Cache hit. return dummyCompileJob(archiveFilePath), nil
return dummyCompileJob(path), nil
} }
// Cache miss, build it now. // Cache miss, build it now.
// Create the destination directory where the components of this library
// (lib.a file, include directory) are placed.
outname := filepath.Base(outdir)
err = os.MkdirAll(filepath.Join(goenv.Get("GOCACHE"), outname), 0o777)
if err != nil {
// Could not create directory (and not because it already exists).
return nil, err
}
// Make headers if needed.
headerPath := filepath.Join(outdir, "include")
if l.makeHeaders != nil {
if _, err = os.Stat(headerPath); err != nil {
temporaryHeaderPath, err := ioutil.TempDir(outdir, "include.tmp*")
if err != nil {
return nil, err
}
defer os.RemoveAll(temporaryHeaderPath)
err = l.makeHeaders(temporaryHeaderPath)
if err != nil {
return nil, err
}
err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil {
return nil, err
}
}
}
remapDir := filepath.Join(os.TempDir(), "tinygo-"+l.name) remapDir := filepath.Join(os.TempDir(), "tinygo-"+l.name)
dir := filepath.Join(tmpdir, "build-lib-"+l.name) dir := filepath.Join(tmpdir, "build-lib-"+l.name)
err = os.Mkdir(dir, 0777) err = os.Mkdir(dir, 0777)
@ -90,7 +119,9 @@ func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error)
// Note: -fdebug-prefix-map is necessary to make the output archive // Note: -fdebug-prefix-map is necessary to make the output archive
// reproducible. Otherwise the temporary directory is stored in the archive // reproducible. Otherwise the temporary directory is stored in the archive
// itself, which varies each run. // itself, which varies each run.
args := append(l.cflags(), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir) target := config.Triple()
args := append(l.cflags(headerPath), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
cpu := config.CPU()
if cpu != "" { if cpu != "" {
args = append(args, "-mcpu="+cpu) args = append(args, "-mcpu="+cpu)
} }
@ -107,19 +138,25 @@ func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error)
// Create job to put all the object files in a single archive. This archive // Create job to put all the object files in a single archive. This archive
// file is the (static) library file. // file is the (static) library file.
var objs []string var objs []string
arpath := filepath.Join(dir, l.name+".a")
job = &compileJob{ job = &compileJob{
description: "ar " + l.name + ".a", description: "ar " + l.name + "/lib.a",
result: arpath, result: filepath.Join(goenv.Get("GOCACHE"), outname, "lib.a"),
run: func(*compileJob) error { run: func(*compileJob) error {
// Create an archive of all object files. // Create an archive of all object files.
err := makeArchive(arpath, objs) f, err := ioutil.TempFile(outdir, "libc.a.tmp*")
if err != nil {
return err
}
err = makeArchive(f, objs)
if err != nil {
return err
}
err = f.Close()
if err != nil { if err != nil {
return err return err
} }
// Store this archive in the cache. // Store this archive in the cache.
_, err = cacheStore(arpath, outfile, l.sourcePaths(target)) return os.Rename(f.Name(), archiveFilePath)
return err
}, },
} }

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

@ -1,6 +1,7 @@
package builder package builder
import ( import (
"os"
"path/filepath" "path/filepath"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
@ -10,7 +11,14 @@ import (
// based on newlib. // based on newlib.
var Picolibc = Library{ var Picolibc = Library{
name: "picolibc", name: "picolibc",
cflags: func() []string { makeHeaders: func(includeDir string) error {
f, err := os.Create(filepath.Join(includeDir, "picolibc.h"))
if err != nil {
return err
}
return f.Close()
},
cflags: func(headerPath string) []string {
picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc") picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc")
return []string{ return []string{
"-Werror", "-Werror",
@ -22,7 +30,7 @@ var Picolibc = Library{
"-nostdlibinc", "-nostdlibinc",
"-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include", "-Xclang", "-internal-isystem", "-Xclang", picolibcDir + "/include",
"-I" + picolibcDir + "/tinystdio", "-I" + picolibcDir + "/tinystdio",
"-I" + goenv.Get("TINYGOROOT") + "/lib/picolibc-include", "-I" + headerPath,
} }
}, },
sourceDir: "lib/picolibc/newlib/libc", sourceDir: "lib/picolibc/newlib/libc",

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

@ -5,6 +5,7 @@ package compileopts
import ( import (
"errors" "errors"
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
@ -197,6 +198,29 @@ func (c *Config) RP2040BootPatch() bool {
return false return false
} }
// LibcPath returns the path to the libc directory. The libc path will be either
// a precompiled libc shipped with a TinyGo build, or a libc path in the cache
// directory (which might not yet be built).
func (c *Config) LibcPath(name string) (path string, precompiled bool) {
// Try to load a precompiled library.
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", c.Triple(), name)
if _, err := os.Stat(precompiledDir); err == nil {
// Found a precompiled library for this OS/architecture. Return the path
// directly.
return precompiledDir, true
}
// No precompiled library found. Determine the path name that will be used
// in the build cache.
var outname string
if c.CPU() != "" {
outname = name + "-" + c.Triple() + "-" + c.CPU()
} else {
outname = name + "-" + c.Triple()
}
return filepath.Join(goenv.Get("GOCACHE"), outname), false
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo // CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing. // preprocessing.
func (c *Config) CFlags() []string { func (c *Config) CFlags() []string {
@ -208,12 +232,12 @@ func (c *Config) CFlags() []string {
case "picolibc": case "picolibc":
root := goenv.Get("TINYGOROOT") root := goenv.Get("TINYGOROOT")
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc") picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
path, _ := c.LibcPath("picolibc")
cflags = append(cflags, cflags = append(cflags,
"-nostdlibinc", "--sysroot="+path,
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"), "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "include"),
"-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"), "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(picolibcDir, "tinystdio"),
) )
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
case "wasi-libc": case "wasi-libc":
root := goenv.Get("TINYGOROOT") root := goenv.Get("TINYGOROOT")
cflags = append(cflags, "--sysroot="+root+"/lib/wasi-libc/sysroot") cflags = append(cflags, "--sysroot="+root+"/lib/wasi-libc/sysroot")

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

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

@ -71,8 +71,8 @@ func moveFile(src, dst string) error {
return os.Remove(src) return os.Remove(src)
} }
// copyFile copies the given file from src to dst. It can copy over // copyFile copies the given file or directory from src to dst. It can copy over
// a possibly already existing file at the destination. // a possibly already existing file (but not directory) at the destination.
func copyFile(src, dst string) error { func copyFile(src, dst string) error {
source, err := os.Open(src) source, err := os.Open(src)
if err != nil { if err != nil {
@ -85,6 +85,23 @@ func copyFile(src, dst string) error {
return err return err
} }
if st.IsDir() {
err := os.Mkdir(dst, st.Mode().Perm())
if err != nil {
return err
}
names, err := source.Readdirnames(0)
if err != nil {
return err
}
for _, name := range names {
err := copyFile(filepath.Join(src, name), filepath.Join(dst, name))
if err != nil {
return err
}
}
return nil
} else {
destination, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, st.Mode()) destination, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, st.Mode())
if err != nil { if err != nil {
return err return err
@ -93,6 +110,7 @@ func copyFile(src, dst string) error {
_, err = io.Copy(destination, source) _, err = io.Copy(destination, source)
return err return err
}
} }
// executeCommand is a simple wrapper to exec.Cmd // executeCommand is a simple wrapper to exec.Cmd
@ -1259,7 +1277,12 @@ func main() {
handleCompilerError(err) handleCompilerError(err)
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
path, err := lib.Load(*target, tmpdir) config := &compileopts.Config{
Target: &compileopts.TargetSpec{
Triple: *target,
},
}
path, err := lib.Load(config, tmpdir)
handleCompilerError(err) handleCompilerError(err)
err = copyFile(path, outpath) err = copyFile(path, outpath)
if err != nil { if err != nil {