|
|
|
package builder
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"tinygo.org/x/go-llvm"
|
|
|
|
)
|
|
|
|
|
|
|
|
// getClangHeaderPath returns the path to the built-in Clang headers. It tries
|
|
|
|
// multiple locations, which should make it find the directory when installed in
|
|
|
|
// various ways.
|
|
|
|
func getClangHeaderPath(TINYGOROOT string) string {
|
|
|
|
// Check whether we're running from the source directory.
|
|
|
|
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
|
|
|
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether we're running from the installation directory.
|
|
|
|
path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
|
|
|
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
|
|
|
// It looks like we are built with a system-installed LLVM. Do a last
|
|
|
|
// attempt: try to use Clang headers relative to the clang binary.
|
|
|
|
llvmMajor := strings.Split(llvm.Version, ".")[0]
|
|
|
|
for _, cmdName := range commands["clang"] {
|
|
|
|
binpath, err := exec.LookPath(cmdName)
|
|
|
|
if err == nil {
|
|
|
|
// This should be the command that will also be used by
|
|
|
|
// execCommand. To avoid inconsistencies, make sure we use the
|
|
|
|
// headers relative to this command.
|
|
|
|
binpath, err = filepath.EvalSymlinks(binpath)
|
|
|
|
if err != nil {
|
|
|
|
// Unexpected.
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
// Example executable:
|
|
|
|
// /usr/lib/llvm-9/bin/clang
|
|
|
|
// Example include path:
|
|
|
|
// /usr/lib/llvm-9/lib64/clang/9.0.1/include/
|
|
|
|
llvmRoot := filepath.Dir(filepath.Dir(binpath))
|
|
|
|
clangVersionRoot := filepath.Join(llvmRoot, "lib64", "clang")
|
|
|
|
dirs64, err64 := ioutil.ReadDir(clangVersionRoot)
|
|
|
|
// Example include path:
|
|
|
|
// /usr/lib/llvm-9/lib/clang/9.0.1/include/
|
|
|
|
clangVersionRoot = filepath.Join(llvmRoot, "lib", "clang")
|
|
|
|
dirs32, err32 := ioutil.ReadDir(clangVersionRoot)
|
|
|
|
if err64 != nil && err32 != nil {
|
|
|
|
// Unexpected.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dirnames := make([]string, len(dirs64)+len(dirs32))
|
|
|
|
dirCount := 0
|
|
|
|
for _, d := range dirs32 {
|
|
|
|
name := d.Name()
|
|
|
|
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
|
|
|
|
dirnames[dirCount] = filepath.Join(llvmRoot, "lib", "clang", name)
|
|
|
|
dirCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, d := range dirs64 {
|
|
|
|
name := d.Name()
|
|
|
|
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
|
|
|
|
dirnames[dirCount] = filepath.Join(llvmRoot, "lib64", "clang", name)
|
|
|
|
dirCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Strings(dirnames)
|
|
|
|
// Check for the highest version first.
|
|
|
|
for i := dirCount - 1; i >= 0; i-- {
|
|
|
|
path := filepath.Join(dirnames[i], "include")
|
|
|
|
_, err := os.Stat(filepath.Join(path, "stdint.h"))
|
|
|
|
if err == nil {
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Could not find it.
|
|
|
|
return ""
|
|
|
|
}
|