main: add fallback mechanism for LLVM commands

On Debian, all LLVM commands have a version suffix (clang-8, ld.lld-8,
wasm-ld-8, etc.). However. Most other distributions only provide a
version prefix for Clang and not for all the other commands.

This commit fixes the issue by trying the command with the version
suffix first and falling back to one without if needed.
Этот коммит содержится в:
Ayke van Laethem 2019-05-03 19:30:54 +02:00 коммит произвёл Ron Evans
родитель 9a54ee4241
коммит 9cad8bd0c8
7 изменённых файлов: 51 добавлений и 46 удалений

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

@ -5,7 +5,6 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
@ -192,13 +191,13 @@ func loadBuiltins(target string) (path string, err error) {
srcs[i] = filepath.Join(builtinsDir, name) srcs[i] = filepath.Join(builtinsDir, name)
} }
if path, err := cacheLoad(outfile, commands["clang"], srcs); path != "" || err != nil { if path, err := cacheLoad(outfile, commands["clang"][0], srcs); path != "" || err != nil {
return path, err return path, err
} }
var cachepath string var cachepath string
err = compileBuiltins(target, func(path string) error { err = compileBuiltins(target, func(path string) error {
path, err := cacheStore(path, outfile, commands["clang"], srcs) path, err := cacheStore(path, outfile, commands["clang"][0], srcs)
cachepath = path cachepath = path
return err return err
}) })
@ -240,10 +239,7 @@ func compileBuiltins(target string, callback func(path string) error) 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 // reproducible. Otherwise the temporary directory is stored in the
// archive itself, which varies each run. // 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) err := execCommand(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
err = cmd.Run()
if err != nil { if err != nil {
return &commandError{"failed to build", srcpath, err} return &commandError{"failed to build", srcpath, err}
} }

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

@ -1,10 +1,33 @@
// +build !darwin
package main package main
// commands used by the compilation process might have different file names on Linux than those used on macOS. import (
var commands = map[string]string{ "errors"
"clang": "clang-8", "os"
"ld.lld": "ld.lld-8", "os/exec"
"wasm-ld": "wasm-ld-8", "strings"
)
// Commands used by the compilation process might have different file names
// across operating systems and distributions.
var commands = map[string][]string{
"clang": {"clang-8"},
"ld.lld": {"ld.lld-8", "ld.lld"},
"wasm-ld": {"wasm-ld-8", "wasm-ld"},
}
func execCommand(cmdNames []string, args ...string) error {
for _, cmdName := range cmdNames {
cmd := exec.Command(cmdName, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
if err, ok := err.(*exec.Error); ok && err.Err == exec.ErrNotFound {
// this command was not found, try the next
continue
}
}
return nil
}
return errors.New("none of these commands were found in your $PATH: " + strings.Join(cmdNames, " "))
} }

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

@ -1,10 +0,0 @@
// +build darwin
package main
// commands used by the compilation process might have different file names on macOS than those used on Linux.
var commands = map[string]string{
"clang": "clang-8",
"ld.lld": "ld.lld",
"wasm-ld": "wasm-ld",
}

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

@ -24,7 +24,7 @@ import "C"
// This version uses the built-in linker when trying to use lld. // This version uses the built-in linker when trying to use lld.
func Link(linker string, flags ...string) error { func Link(linker string, flags ...string) error {
switch linker { switch linker {
case "ld.lld", commands["ld.lld"]: case "ld.lld":
flags = append([]string{"tinygo:" + linker}, flags...) flags = append([]string{"tinygo:" + linker}, flags...)
var cflag *C.char var cflag *C.char
buf := C.calloc(C.size_t(len(flags)), C.size_t(unsafe.Sizeof(cflag))) buf := C.calloc(C.size_t(len(flags)), C.size_t(unsafe.Sizeof(cflag)))
@ -39,7 +39,7 @@ func Link(linker string, flags ...string) error {
return errors.New("failed to link using built-in ld.lld") return errors.New("failed to link using built-in ld.lld")
} }
return nil return nil
case "wasm-ld", commands["wasm-ld"]: case "wasm-ld":
flags = append([]string{"tinygo:" + linker}, flags...) flags = append([]string{"tinygo:" + linker}, flags...)
var cflag *C.char var cflag *C.char
buf := C.calloc(C.size_t(len(flags)), C.size_t(unsafe.Sizeof(cflag))) buf := C.calloc(C.size_t(len(flags)), C.size_t(unsafe.Sizeof(cflag)))
@ -57,6 +57,9 @@ func Link(linker string, flags ...string) error {
return nil return nil
default: default:
// Fall back to external command. // Fall back to external command.
if cmdNames, ok := commands[linker]; ok {
return execCommand(cmdNames, flags...)
}
cmd := exec.Command(linker, flags...) cmd := exec.Command(linker, flags...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr

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

@ -14,6 +14,9 @@ import (
// //
// This version always runs the linker as an external command. // This version always runs the linker as an external command.
func Link(linker string, flags ...string) error { func Link(linker string, flags ...string) error {
if cmdNames, ok := commands[linker]; ok {
return execCommand(cmdNames, flags...)
}
cmd := exec.Command(linker, flags...) cmd := exec.Command(linker, flags...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr

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

@ -222,14 +222,11 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
for i, path := range spec.ExtraFiles { for i, path := range spec.ExtraFiles {
abspath := filepath.Join(root, path) abspath := filepath.Join(root, path)
outpath := filepath.Join(dir, "extra-"+strconv.Itoa(i)+"-"+filepath.Base(path)+".o") outpath := filepath.Join(dir, "extra-"+strconv.Itoa(i)+"-"+filepath.Base(path)+".o")
cmdName := spec.Compiler cmdNames := []string{spec.Compiler}
if name, ok := commands[cmdName]; ok { if names, ok := commands[spec.Compiler]; ok {
cmdName = name cmdNames = names
} }
cmd := exec.Command(cmdName, append(cflags, "-c", "-o", outpath, abspath)...) err := execCommand(cmdNames, append(cflags, "-c", "-o", outpath, abspath)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil { if err != nil {
return &commandError{"failed to build", path, err} return &commandError{"failed to build", path, err}
} }
@ -241,14 +238,11 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
for _, file := range pkg.CFiles { for _, file := range pkg.CFiles {
path := filepath.Join(pkg.Package.Dir, file) path := filepath.Join(pkg.Package.Dir, file)
outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+file+".o") outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+file+".o")
cmdName := spec.Compiler cmdNames := []string{spec.Compiler}
if name, ok := commands[cmdName]; ok { if names, ok := commands[spec.Compiler]; ok {
cmdName = name cmdNames = names
} }
cmd := exec.Command(cmdName, append(cflags, "-c", "-o", outpath, path)...) err := execCommand(cmdNames, append(cflags, "-c", "-o", outpath, path)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil { if err != nil {
return &commandError{"failed to build", path, err} return &commandError{"failed to build", path, err}
} }
@ -257,11 +251,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
} }
// Link the object files together. // Link the object files together.
if linker, ok := commands[spec.Linker]; ok { err = Link(spec.Linker, ldflags...)
err = Link(linker, ldflags...)
} else {
err = Link(spec.Linker, ldflags...)
}
if err != nil { if err != nil {
return &commandError{"failed to link", executable, err} return &commandError{"failed to link", executable, err}
} }

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

@ -211,7 +211,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
GOOS: goos, GOOS: goos,
GOARCH: goarch, GOARCH: goarch,
BuildTags: []string{goos, goarch}, BuildTags: []string{goos, goarch},
Compiler: commands["clang"], Compiler: "clang",
Linker: "cc", Linker: "cc",
GDB: "gdb", GDB: "gdb",
GDBCmds: []string{"run"}, GDBCmds: []string{"run"},