diff --git a/builtins.go b/builtins.go index 75b6592a..8ac127f7 100644 --- a/builtins.go +++ b/builtins.go @@ -5,7 +5,6 @@ import ( "io" "io/ioutil" "os" - "os/exec" "path/filepath" "strings" "time" @@ -192,13 +191,13 @@ func loadBuiltins(target string) (path string, err error) { 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 } var cachepath string 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 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 // 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 - err = cmd.Run() + 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) if err != nil { return &commandError{"failed to build", srcpath, err} } diff --git a/commands.go b/commands.go index a975b5b2..5f7ff8c1 100644 --- a/commands.go +++ b/commands.go @@ -1,10 +1,33 @@ -// +build !darwin - package main -// commands used by the compilation process might have different file names on Linux than those used on macOS. -var commands = map[string]string{ - "clang": "clang-8", - "ld.lld": "ld.lld-8", - "wasm-ld": "wasm-ld-8", +import ( + "errors" + "os" + "os/exec" + "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, " ")) } diff --git a/commands_macos.go b/commands_macos.go deleted file mode 100644 index 9ec428ec..00000000 --- a/commands_macos.go +++ /dev/null @@ -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", -} diff --git a/linker-builtin.go b/linker-builtin.go index c8987938..d0a01681 100644 --- a/linker-builtin.go +++ b/linker-builtin.go @@ -24,7 +24,7 @@ import "C" // This version uses the built-in linker when trying to use lld. func Link(linker string, flags ...string) error { switch linker { - case "ld.lld", commands["ld.lld"]: + case "ld.lld": flags = append([]string{"tinygo:" + linker}, flags...) var cflag *C.char 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 nil - case "wasm-ld", commands["wasm-ld"]: + case "wasm-ld": flags = append([]string{"tinygo:" + linker}, flags...) var cflag *C.char 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 default: // Fall back to external command. + if cmdNames, ok := commands[linker]; ok { + return execCommand(cmdNames, flags...) + } cmd := exec.Command(linker, flags...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr diff --git a/linker-external.go b/linker-external.go index 446b6808..48e4d2ec 100644 --- a/linker-external.go +++ b/linker-external.go @@ -14,6 +14,9 @@ import ( // // This version always runs the linker as an external command. func Link(linker string, flags ...string) error { + if cmdNames, ok := commands[linker]; ok { + return execCommand(cmdNames, flags...) + } cmd := exec.Command(linker, flags...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr diff --git a/main.go b/main.go index a06825ee..b662d65c 100644 --- a/main.go +++ b/main.go @@ -222,14 +222,11 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act for i, path := range spec.ExtraFiles { abspath := filepath.Join(root, path) outpath := filepath.Join(dir, "extra-"+strconv.Itoa(i)+"-"+filepath.Base(path)+".o") - cmdName := spec.Compiler - if name, ok := commands[cmdName]; ok { - cmdName = name + cmdNames := []string{spec.Compiler} + if names, ok := commands[spec.Compiler]; ok { + cmdNames = names } - cmd := exec.Command(cmdName, append(cflags, "-c", "-o", outpath, abspath)...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() + err := execCommand(cmdNames, append(cflags, "-c", "-o", outpath, abspath)...) if err != nil { 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 { path := filepath.Join(pkg.Package.Dir, file) outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+file+".o") - cmdName := spec.Compiler - if name, ok := commands[cmdName]; ok { - cmdName = name + cmdNames := []string{spec.Compiler} + if names, ok := commands[spec.Compiler]; ok { + cmdNames = names } - cmd := exec.Command(cmdName, append(cflags, "-c", "-o", outpath, path)...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() + err := execCommand(cmdNames, append(cflags, "-c", "-o", outpath, path)...) if err != nil { 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. - if linker, ok := commands[spec.Linker]; ok { - err = Link(linker, ldflags...) - } else { - err = Link(spec.Linker, ldflags...) - } + err = Link(spec.Linker, ldflags...) if err != nil { return &commandError{"failed to link", executable, err} } diff --git a/target.go b/target.go index 16970215..546883f3 100644 --- a/target.go +++ b/target.go @@ -211,7 +211,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { GOOS: goos, GOARCH: goarch, BuildTags: []string{goos, goarch}, - Compiler: commands["clang"], + Compiler: "clang", Linker: "cc", GDB: "gdb", GDBCmds: []string{"run"},