gllvm/shared/sanity.go

226 lines
5.9 KiB
Go
Raw Normal View History

package shared
2017-07-10 22:01:21 +02:00
import (
"bytes"
"os"
"os/exec"
2017-07-21 01:11:44 +02:00
"path/filepath"
2017-07-10 22:01:21 +02:00
"runtime"
"strings"
)
const explainLLVMCCNAME = `
2017-07-10 22:01:21 +02:00
If your clang compiler is not called clang, but something else, then
you will need to set the environment variable LLVM_CC_NAME to the
appropriate string. For example if your clang is called clang-3.5 then
LLVM_CC_NAME should be set to clang-3.5.
`
const explainLLVMCXXNAME = `
2017-07-10 22:01:21 +02:00
If your clang++ compiler is not called clang++, but something else,
then you will need to set the environment variable LLVM_CXX_NAME to
the appropriate string. For example if your clang++ is called ++clang
then LLVM_CC_NAME should be set to ++clang.
`
const explainLLVMCOMPILERPATH = `
2017-07-10 22:01:21 +02:00
Your compiler should either be in your PATH, or else located where the
environment variable LLVM_COMPILER_PATH indicates. It can also be used
to indicate the directory that contains the other LLVM tools such as
llvm-link, and llvm-ar.
`
const explainLLVMLINKNAME = `
2017-07-10 22:01:21 +02:00
If your llvm linker is not called llvm-link, but something else, then
you will need to set the environment variable LLVM_LINK_NAME to the
appropriate string. For example if your llvm-link is called llvm-link-3.5 then
LLVM_LINK_NAME should be set to llvm-link-3.5.
`
const explainLLVMARNAME = `
2017-07-10 22:01:21 +02:00
If your llvm archiver is not called llvm-ar, but something else,
then you will need to set the environment variable LLVM_AR_NAME to
the appropriate string. For example if your llvm-ar is called llvm-ar-3.5
then LLVM_AR_NAME should be set to llvm-ar-3.5.
`
// SanityCheck performs the environmental sanity check.
2017-07-10 22:01:21 +02:00
//
// Performs the following checks in order:
// 0. Check the logging
2017-07-10 22:01:21 +02:00
// 1. Check that the OS is supported.
// 2. Checks that the compiler settings make sense.
// 3. Checks that the needed LLVM utilities exists.
// 4. Check that the store, if set, exists.
//
func SanityCheck() {
checkLogging()
2017-07-10 22:01:21 +02:00
checkOS()
if !checkCompilers() {
2017-07-10 22:01:21 +02:00
os.Exit(1)
}
if !checkAuxiliaries() {
2017-07-10 22:01:21 +02:00
os.Exit(1)
}
checkStore()
}
func checkOS() {
2017-07-10 22:01:21 +02:00
platform := runtime.GOOS
if platform == "darwin" || platform == "linux" || platform == "freebsd" {
LogWrite("Happily sitting atop \"%s\" operating system.\n\n", platform)
2017-07-10 22:01:21 +02:00
return
}
LogFatal("We do not support the OS %s", platform)
2017-07-10 22:01:21 +02:00
}
func checkCompilers() bool {
cc := GetCompilerExecName("clang")
ccOK, ccVersion, _ := checkExecutable(cc, "-v")
2017-07-10 22:01:21 +02:00
if !ccOK {
LogError("The C compiler %s was not found or not executable.\nBetter not try using gclang!\n", cc)
2017-07-10 22:01:21 +02:00
} else {
LogWrite("The C compiler %s is:\n\n\t%s\n\n", cc, extractLine(ccVersion, 0))
2017-07-10 22:01:21 +02:00
}
cxx := GetCompilerExecName("clang++")
cxxOK, cxxVersion, _ := checkExecutable(cxx, "-v")
2017-07-10 22:01:21 +02:00
if !ccOK {
LogError("The CXX compiler %s was not found or not executable.\nBetter not try using gclang++!\n", cxx)
2017-07-10 22:01:21 +02:00
} else {
LogWrite("The CXX compiler %s is:\n\n\t%s\n\n", cxx, extractLine(cxxVersion, 0))
2017-07-10 22:01:21 +02:00
}
//FIXME: why "or" rather than "and"?
2017-07-10 22:01:21 +02:00
return ccOK || cxxOK
}
func extractLine(version string, n int) string {
if len(version) == 0 {
return version
}
lines := strings.Split(version, "\n")
var line string
lenLines := len(lines)
if n < lenLines {
2017-07-10 22:01:21 +02:00
line = lines[n]
} else {
line = lines[lenLines-1]
2017-07-10 22:01:21 +02:00
}
return strings.TrimSpace(line)
}
// FIXME: this and execCmd in utils.go could be one routine, if that seems reasonable, or is it overboard?
2017-07-10 22:01:21 +02:00
// Executes a command then returns true for success, false if there was an error, err is either nil or the error.
func checkExecutable(cmdExecName string, varg string) (success bool, output string, err error) {
2017-07-10 22:01:21 +02:00
cmd := exec.Command(cmdExecName, varg)
var out bytes.Buffer
//strangely clang writes it's version out on stderr
//so we conflate the two to be tolerant.
2017-07-10 22:01:21 +02:00
cmd.Stdout = &out
cmd.Stderr = &out
cmd.Stdin = os.Stdin
err = cmd.Run()
success = (err == nil)
output = out.String()
return
}
func checkAuxiliaries() bool {
linkerName := LLVMLINKName
archiverName := LLVMARName
2017-07-10 22:01:21 +02:00
if linkerName == "" {
linkerName = "llvm-link"
}
if archiverName == "" {
archiverName = "llvm-ar"
}
2017-07-21 01:11:44 +02:00
linkerName = filepath.Join(LLVMToolChainBinDir, linkerName)
linkerOK, linkerVersion, _ := checkExecutable(linkerName, "-version")
2017-07-10 22:01:21 +02:00
if !linkerOK {
LogError("The bitcode linker %s was not found or not executable.\nBetter not try using get-bc!\n", linkerName)
LogError(explainLLVMLINKNAME)
2017-07-10 22:01:21 +02:00
} else {
LogWrite("The bitcode linker %s is:\n\n\t%s\n\n", linkerName, extractLine(linkerVersion, 1))
2017-07-10 22:01:21 +02:00
}
2017-07-21 01:11:44 +02:00
archiverName = filepath.Join(LLVMToolChainBinDir, archiverName)
archiverOK, archiverVersion, _ := checkExecutable(archiverName, "-version")
2017-07-10 22:01:21 +02:00
if !archiverOK {
LogError("The bitcode archiver %s was not found or not executable.\nBetter not try using get-bc!\n", archiverName)
LogError(explainLLVMARNAME)
2017-07-10 22:01:21 +02:00
} else {
LogWrite("The bitcode archiver %s is:\n\n\t%s\n\n", archiverName, extractLine(archiverVersion, 1))
2017-07-10 22:01:21 +02:00
}
return linkerOK && archiverOK
2017-07-10 22:01:21 +02:00
}
func checkStore() {
storeDir := LLVMBitcodeStorePath
2017-07-10 22:01:21 +02:00
if storeDir != "" {
finfo, err := os.Stat(storeDir)
if err != nil && os.IsNotExist(err) {
LogError("The bitcode archive %s does not exist!\n\n", storeDir)
2017-07-10 22:01:21 +02:00
return
}
if !finfo.Mode().IsDir() {
LogError("The bitcode archive %s is not a directory!\n\n", storeDir)
2017-07-10 22:01:21 +02:00
return
}
LogWrite("Using the bitcode archive %s\n\n", storeDir)
2017-07-10 22:01:21 +02:00
return
}
LogWrite("Not using a bitcode store.\n\n")
}
func checkLogging() {
if LLVMLoggingFile != "" {
// override the redirection so we output to the terminal (would be unnecessary
// if we multiplexed in logging.go)
loggingFilePointer = os.Stderr
LogWrite("\nLogging output directed to %s.\n", LLVMLoggingFile)
} else {
LogWrite("\nLogging output to standard error.\n")
}
if LLVMLoggingLevel != "" {
if _, ok := loggingLevels[LLVMLoggingLevel]; ok {
LogWrite("Logging level is set to %s.\n\n", LLVMLoggingLevel)
} else {
LogWrite("Logging level is set to UNKNOWN level %s, using default of ERROR.\n\n", LLVMLoggingLevel)
}
} else {
LogWrite("Logging level not set, using default of ERROR.\n\n")
}
2017-07-10 22:01:21 +02:00
}