2017-08-26 01:34:03 +02:00
|
|
|
//
|
|
|
|
// OCCAM
|
|
|
|
//
|
|
|
|
// Copyright (c) 2017, SRI International
|
|
|
|
//
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright notice, this
|
|
|
|
// list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// * Neither the name of SRI International nor the names of its contributors may
|
|
|
|
// be used to endorse or promote products derived from this software without
|
|
|
|
// specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
|
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
|
|
|
2017-07-11 19:52:05 +02:00
|
|
|
package shared
|
2017-07-10 22:01:21 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-05-03 00:59:34 +02:00
|
|
|
"flag"
|
2017-07-10 22:01:21 +02:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2017-07-21 01:11:44 +02:00
|
|
|
"path/filepath"
|
2017-07-10 22:01:21 +02:00
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
`
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
`
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
`
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
`
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
`
|
|
|
|
|
2018-05-03 00:59:34 +02:00
|
|
|
type sanityArgs struct {
|
|
|
|
Environment bool
|
|
|
|
}
|
|
|
|
|
2017-07-11 19:52:05 +02:00
|
|
|
// SanityCheck performs the environmental sanity check.
|
2017-07-10 22:01:21 +02:00
|
|
|
//
|
|
|
|
// Performs the following checks in order:
|
2017-07-11 19:52:05 +02:00
|
|
|
// 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.
|
|
|
|
//
|
2017-07-11 19:52:05 +02:00
|
|
|
func SanityCheck() {
|
|
|
|
|
2018-05-03 00:59:34 +02:00
|
|
|
sa := parseSanitySwitches()
|
|
|
|
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("\nVersion info: gsanity-check version %v\nReleased: %v\n", gllvmVersion, gllvmReleaseDate)
|
2018-04-18 15:58:47 +02:00
|
|
|
|
2018-05-03 00:59:34 +02:00
|
|
|
if sa.Environment {
|
|
|
|
printEnvironment()
|
|
|
|
}
|
|
|
|
|
2017-07-11 19:52:05 +02:00
|
|
|
checkLogging()
|
2017-07-10 22:01:21 +02:00
|
|
|
|
|
|
|
checkOS()
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
if !checkCompilers() {
|
2017-07-10 22:01:21 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
if !checkAuxiliaries() {
|
2017-07-10 22:01:21 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStore()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-05-03 00:59:34 +02:00
|
|
|
func parseSanitySwitches() (sa sanityArgs) {
|
|
|
|
sa = sanityArgs{
|
|
|
|
Environment: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
environmentPtr := flag.Bool("e", false, "show environment")
|
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
sa.Environment = *environmentPtr
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-07-10 22:11:46 +02:00
|
|
|
func checkOS() {
|
2017-07-10 22:01:21 +02:00
|
|
|
|
|
|
|
platform := runtime.GOOS
|
|
|
|
|
2018-04-18 15:58:47 +02:00
|
|
|
if platform == osDARWIN || platform == osLINUX || platform == osFREEBSD {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("Happily sitting atop \"%s\" operating system.\n\n", platform)
|
2017-07-10 22:01:21 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("We do not support the OS %s", platform)
|
|
|
|
os.Exit(1)
|
2018-05-04 23:25:44 +02:00
|
|
|
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func checkCompilers() bool {
|
|
|
|
|
2017-07-11 19:52:05 +02:00
|
|
|
cc := GetCompilerExecName("clang")
|
2017-07-10 22:14:34 +02:00
|
|
|
ccOK, ccVersion, _ := checkExecutable(cc, "-v")
|
2017-07-10 22:01:21 +02:00
|
|
|
if !ccOK {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The C compiler %s was not found or not executable.\nBetter not try using gclang!\n", cc)
|
|
|
|
informUser(explainLLVMCOMPILERPATH)
|
|
|
|
informUser(explainLLVMCCNAME)
|
2018-04-18 15:58:47 +02:00
|
|
|
|
2017-07-10 22:01:21 +02:00
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The C compiler %s is:\n\n\t%s\n\n", cc, extractLine(ccVersion, 0))
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 19:52:05 +02:00
|
|
|
cxx := GetCompilerExecName("clang++")
|
2017-07-10 22:14:34 +02:00
|
|
|
cxxOK, cxxVersion, _ := checkExecutable(cxx, "-v")
|
2017-07-10 22:01:21 +02:00
|
|
|
if !ccOK {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The CXX compiler %s was not found or not executable.\nBetter not try using gclang++!\n", cxx)
|
|
|
|
informUser(explainLLVMCOMPILERPATH)
|
|
|
|
informUser(explainLLVMCXXNAME)
|
2017-07-10 22:01:21 +02:00
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The CXX compiler %s is:\n\n\t%s\n\n", cxx, extractLine(cxxVersion, 0))
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|
|
|
|
|
2018-05-11 16:13:13 +02:00
|
|
|
//FIXME: why "or" rather than "and"? BECAUSE: if you only need CC, not having CXX is not an error.
|
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)
|
2017-07-10 22:11:46 +02:00
|
|
|
if n < lenLines {
|
2017-07-10 22:01:21 +02:00
|
|
|
line = lines[n]
|
|
|
|
} else {
|
2017-07-10 22:11:46 +02:00
|
|
|
line = lines[lenLines-1]
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return strings.TrimSpace(line)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Executes a command then returns true for success, false if there was an error, err is either nil or the error.
|
2017-07-10 22:14:34 +02:00
|
|
|
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
|
2017-07-11 19:52:05 +02:00
|
|
|
//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()
|
2018-05-09 00:11:42 +02:00
|
|
|
LogInfo("checkExecutable: %s %s returned %s\n", cmdExecName, varg, output)
|
|
|
|
LogInfo("checkExecutable: returning (%s %s %s)\n", success, output, err)
|
2017-07-10 22:01:21 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkAuxiliaries() bool {
|
2017-07-11 19:52:05 +02:00
|
|
|
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)
|
|
|
|
|
2017-07-10 22:14:34 +02:00
|
|
|
linkerOK, linkerVersion, _ := checkExecutable(linkerName, "-version")
|
2017-07-10 22:01:21 +02:00
|
|
|
|
2018-05-09 00:11:42 +02:00
|
|
|
// iam: 5/8/2018 3.4 llvm-link and llvm-ar return exit status 1 for -version. GO FIGURE.
|
|
|
|
if !linkerOK && !strings.Contains(linkerVersion, "LLVM") {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The bitcode linker %s was not found or not executable.\nBetter not try using get-bc!\n", linkerName)
|
|
|
|
informUser(explainLLVMLINKNAME)
|
2017-07-10 22:01:21 +02:00
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("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)
|
2017-07-10 22:14:34 +02:00
|
|
|
archiverOK, archiverVersion, _ := checkExecutable(archiverName, "-version")
|
2017-07-10 22:01:21 +02:00
|
|
|
|
2018-05-09 00:11:42 +02:00
|
|
|
// iam: 5/8/2018 3.4 llvm-link and llvm-ar return exit status 1 for -version. GO FIGURE.
|
|
|
|
if !archiverOK && !strings.Contains(linkerVersion, "LLVM") {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The bitcode archiver %s was not found or not executable.\nBetter not try using get-bc!\n", archiverName)
|
|
|
|
informUser(explainLLVMARNAME)
|
2017-07-10 22:01:21 +02:00
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The bitcode archiver %s is:\n\n\t%s\n\n", archiverName, extractLine(archiverVersion, 1))
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|
|
|
|
|
2017-07-13 17:57:15 +02:00
|
|
|
return linkerOK && archiverOK
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func checkStore() {
|
2017-07-11 19:52:05 +02:00
|
|
|
storeDir := LLVMBitcodeStorePath
|
2017-07-10 22:01:21 +02:00
|
|
|
|
|
|
|
if storeDir != "" {
|
|
|
|
finfo, err := os.Stat(storeDir)
|
|
|
|
if err != nil && os.IsNotExist(err) {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The bitcode archive %s does not exist!\n\n", storeDir)
|
2017-07-10 22:01:21 +02:00
|
|
|
return
|
|
|
|
}
|
2017-07-10 22:11:46 +02:00
|
|
|
if !finfo.Mode().IsDir() {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("The bitcode archive %s is not a directory!\n\n", storeDir)
|
2017-07-10 22:01:21 +02:00
|
|
|
return
|
|
|
|
}
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("Using the bitcode archive %s\n\n", storeDir)
|
2017-07-10 22:01:21 +02:00
|
|
|
return
|
|
|
|
}
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("Not using a bitcode store.\n\n")
|
2017-07-11 19:52:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func checkLogging() {
|
|
|
|
|
|
|
|
if LLVMLoggingFile != "" {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("\nLogging output directed to %s.\n", LLVMLoggingFile)
|
2017-07-11 19:52:05 +02:00
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("\nLogging output to standard error.\n")
|
2017-07-11 19:52:05 +02:00
|
|
|
}
|
|
|
|
if LLVMLoggingLevel != "" {
|
|
|
|
if _, ok := loggingLevels[LLVMLoggingLevel]; ok {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("Logging level is set to %s.\n\n", LLVMLoggingLevel)
|
2017-07-11 19:52:05 +02:00
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("Logging level is set to UNKNOWN level %s, using default of ERROR.\n\n", LLVMLoggingLevel)
|
2017-07-11 19:52:05 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-05-04 22:28:48 +02:00
|
|
|
informUser("Logging level not set, using default of WARNING.\n\n")
|
2017-07-11 19:52:05 +02:00
|
|
|
}
|
2017-07-10 22:01:21 +02:00
|
|
|
}
|