2017-07-05 17:14:11 +02:00
|
|
|
package shared
|
|
|
|
|
2017-06-22 01:34:56 +02:00
|
|
|
import (
|
2017-06-29 21:38:04 +02:00
|
|
|
"io"
|
2017-06-28 23:13:56 +02:00
|
|
|
"io/ioutil"
|
2017-06-29 21:38:04 +02:00
|
|
|
"os"
|
2017-06-28 23:13:56 +02:00
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
2017-06-29 21:38:04 +02:00
|
|
|
"strings"
|
2017-06-28 23:13:56 +02:00
|
|
|
"sync"
|
2017-06-22 01:34:56 +02:00
|
|
|
)
|
|
|
|
|
2017-06-30 02:39:37 +02:00
|
|
|
type bitcodeToObjectLink struct {
|
2017-06-29 21:38:04 +02:00
|
|
|
bcPath string
|
2017-06-28 23:13:56 +02:00
|
|
|
objPath string
|
2017-06-27 01:06:51 +02:00
|
|
|
}
|
|
|
|
|
2017-07-05 17:14:11 +02:00
|
|
|
func Compile(args []string, compilerName string) (exitCode int) {
|
2017-06-30 23:41:30 +02:00
|
|
|
exitCode = 0
|
|
|
|
//in the configureOnly case we have to know the exit code of the compile
|
|
|
|
//because that is how configure figures out what it can and cannot do.
|
2017-07-01 00:09:30 +02:00
|
|
|
|
2017-06-30 23:41:30 +02:00
|
|
|
var ok bool = true
|
|
|
|
|
2017-06-28 23:13:56 +02:00
|
|
|
var compilerExecName = getCompilerExecName(compilerName)
|
|
|
|
var configureOnly bool
|
2017-06-30 19:52:53 +02:00
|
|
|
if ConfigureOnly != "" {
|
2017-06-28 23:13:56 +02:00
|
|
|
configureOnly = true
|
|
|
|
}
|
|
|
|
var pr = parse(args)
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// If configure only is set, just execute the compiler
|
2017-06-30 23:41:30 +02:00
|
|
|
|
2017-06-28 23:13:56 +02:00
|
|
|
if configureOnly {
|
|
|
|
wg.Add(1)
|
2017-06-30 23:41:30 +02:00
|
|
|
go execCompile(compilerExecName, pr, &wg, &ok)
|
2017-06-28 23:13:56 +02:00
|
|
|
wg.Wait()
|
|
|
|
// Else try to build bitcode as well
|
2017-06-30 23:41:30 +02:00
|
|
|
|
|
|
|
if !ok {
|
|
|
|
exitCode = 1
|
|
|
|
}
|
|
|
|
|
2017-06-28 23:13:56 +02:00
|
|
|
} else {
|
2017-06-30 02:39:37 +02:00
|
|
|
var bcObjLinks []bitcodeToObjectLink
|
2017-06-28 23:13:56 +02:00
|
|
|
var newObjectFiles []string
|
2017-06-30 23:41:30 +02:00
|
|
|
|
2017-06-28 23:13:56 +02:00
|
|
|
wg.Add(2)
|
2017-06-30 23:41:30 +02:00
|
|
|
go execCompile(compilerExecName, pr, &wg, &ok)
|
2017-06-28 23:13:56 +02:00
|
|
|
go buildAndAttachBitcode(compilerExecName, pr, &bcObjLinks, &newObjectFiles, &wg)
|
|
|
|
wg.Wait()
|
|
|
|
|
2017-07-01 00:09:30 +02:00
|
|
|
//grok the exit code
|
2017-06-30 23:41:30 +02:00
|
|
|
if !ok {
|
|
|
|
exitCode = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
//FIXME: (if the compile went bad, why are we even trying to do more here)
|
|
|
|
// When objects and bitcode are built we can attach bitcode paths
|
2017-06-28 23:13:56 +02:00
|
|
|
// to object files and link
|
|
|
|
for _, link := range bcObjLinks {
|
|
|
|
attachBitcodePathToObject(link.bcPath, link.objPath)
|
|
|
|
}
|
|
|
|
if !pr.IsCompileOnly {
|
|
|
|
compileTimeLinkFiles(compilerExecName, pr, newObjectFiles)
|
|
|
|
}
|
|
|
|
}
|
2017-06-30 23:41:30 +02:00
|
|
|
return
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
2017-06-27 01:06:51 +02:00
|
|
|
// Compiles bitcode files and mutates the list of bc->obj links to perform + the list of
|
|
|
|
// new object files to link
|
2017-06-30 02:46:30 +02:00
|
|
|
func buildAndAttachBitcode(compilerExecName string, pr parserResult, bcObjLinks *[]bitcodeToObjectLink, newObjectFiles *[]string, wg *sync.WaitGroup) {
|
2017-06-28 23:13:56 +02:00
|
|
|
defer (*wg).Done()
|
|
|
|
// If nothing to do, exit silently
|
|
|
|
if !pr.IsEmitLLVM && !pr.IsAssembly && !pr.IsAssembleOnly &&
|
|
|
|
!(pr.IsDependencyOnly && !pr.IsCompileOnly) && !pr.IsPreprocessOnly {
|
|
|
|
var hidden = !pr.IsCompileOnly
|
|
|
|
|
|
|
|
if len(pr.InputFiles) == 1 && pr.IsCompileOnly {
|
|
|
|
var srcFile = pr.InputFiles[0]
|
|
|
|
objFile, bcFile := getArtifactNames(pr, 0, hidden)
|
|
|
|
buildBitcodeFile(compilerExecName, pr, srcFile, bcFile)
|
2017-06-30 02:39:37 +02:00
|
|
|
*bcObjLinks = append(*bcObjLinks, bitcodeToObjectLink{bcPath: bcFile, objPath: objFile})
|
2017-06-28 23:13:56 +02:00
|
|
|
} else {
|
|
|
|
for i, srcFile := range pr.InputFiles {
|
|
|
|
objFile, bcFile := getArtifactNames(pr, i, hidden)
|
|
|
|
if hidden {
|
|
|
|
buildObjectFile(compilerExecName, pr, srcFile, objFile)
|
|
|
|
*newObjectFiles = append(*newObjectFiles, objFile)
|
|
|
|
}
|
|
|
|
if strings.HasSuffix(srcFile, ".bc") {
|
2017-06-30 02:39:37 +02:00
|
|
|
*bcObjLinks = append(*bcObjLinks, bitcodeToObjectLink{bcPath: srcFile, objPath: objFile})
|
2017-06-28 23:13:56 +02:00
|
|
|
} else {
|
|
|
|
buildBitcodeFile(compilerExecName, pr, srcFile, bcFile)
|
2017-06-30 02:39:37 +02:00
|
|
|
*bcObjLinks = append(*bcObjLinks, bitcodeToObjectLink{bcPath: bcFile, objPath: objFile})
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func attachBitcodePathToObject(bcFile, objFile string) {
|
2017-06-28 23:13:56 +02:00
|
|
|
// We can only attach a bitcode path to certain file types
|
|
|
|
switch filepath.Ext(objFile) {
|
2017-06-29 21:38:04 +02:00
|
|
|
case
|
2017-06-28 23:13:56 +02:00
|
|
|
".o",
|
|
|
|
".lo",
|
|
|
|
".os",
|
|
|
|
".So",
|
|
|
|
".po":
|
|
|
|
// Store bitcode path to temp file
|
|
|
|
var absBcPath, _ = filepath.Abs(bcFile)
|
2017-06-29 21:38:04 +02:00
|
|
|
tmpContent := []byte(absBcPath + "\n")
|
2017-06-28 23:13:56 +02:00
|
|
|
tmpFile, err := ioutil.TempFile("", "gllvm")
|
|
|
|
if err != nil {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("attachBitcodePathToObject: %v\n", err)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
|
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
if _, err := tmpFile.Write(tmpContent); err != nil {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("attachBitcodePathToObject: %v\n", err)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
|
|
|
if err := tmpFile.Close(); err != nil {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("attachBitcodePathToObject: %v\n", err)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Let's write the bitcode section
|
|
|
|
var attachCmd string
|
|
|
|
var attachCmdArgs []string
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
attachCmd = "ld"
|
2017-06-30 20:54:59 +02:00
|
|
|
attachCmdArgs = []string{"-r", "-keep_private_externs", objFile, "-sectcreate", DarwinSegmentName, DarwinSectionName, tmpFile.Name(), "-o", objFile}
|
2017-06-28 23:13:56 +02:00
|
|
|
} else {
|
|
|
|
attachCmd = "objcopy"
|
2017-06-30 20:54:59 +02:00
|
|
|
attachCmdArgs = []string{"--add-section", ELFSectionName + "=" + tmpFile.Name(), objFile}
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Run the attach command and ignore errors
|
2017-06-30 21:17:27 +02:00
|
|
|
execCmd(attachCmd, attachCmdArgs, "")
|
2017-06-28 23:13:56 +02:00
|
|
|
|
|
|
|
// Copy bitcode file to store, if necessary
|
2017-06-30 19:52:53 +02:00
|
|
|
if bcStorePath := os.Getenv(BitcodeStorePath); bcStorePath != "" {
|
2017-06-28 23:13:56 +02:00
|
|
|
destFilePath := path.Join(bcStorePath, getHashedPath(absBcPath))
|
|
|
|
in, _ := os.Open(absBcPath)
|
|
|
|
defer in.Close()
|
|
|
|
out, _ := os.Create(destFilePath)
|
2017-06-29 21:38:04 +02:00
|
|
|
defer out.Close()
|
2017-06-28 23:13:56 +02:00
|
|
|
io.Copy(out, in)
|
|
|
|
out.Sync()
|
|
|
|
}
|
|
|
|
}
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
2017-06-30 02:46:30 +02:00
|
|
|
func compileTimeLinkFiles(compilerExecName string, pr parserResult, objFiles []string) {
|
2017-06-28 23:13:56 +02:00
|
|
|
var outputFile = pr.OutputFilename
|
|
|
|
if outputFile == "" {
|
|
|
|
outputFile = "a.out"
|
|
|
|
}
|
2017-07-03 20:21:47 +02:00
|
|
|
args := pr.LinkArgs
|
2017-06-28 23:13:56 +02:00
|
|
|
args = append(args, objFiles...)
|
|
|
|
args = append(args, "-o", outputFile)
|
2017-06-30 19:00:25 +02:00
|
|
|
success, err := execCmd(compilerExecName, args, "")
|
|
|
|
if !success {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("Failed to link: %v.", err)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tries to build the specified source file to object
|
2017-06-30 02:46:30 +02:00
|
|
|
func buildObjectFile(compilerExecName string, pr parserResult, srcFile string, objFile string) {
|
2017-06-28 23:13:56 +02:00
|
|
|
args := pr.CompileArgs[:]
|
|
|
|
args = append(args, srcFile, "-c", "-o", objFile)
|
2017-06-30 19:00:25 +02:00
|
|
|
success, err := execCmd(compilerExecName, args, "")
|
|
|
|
if !success {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("Failed to build object file for %s because: %v\n", srcFile, err)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tries to build the specified source file to bitcode
|
2017-06-30 02:46:30 +02:00
|
|
|
func buildBitcodeFile(compilerExecName string, pr parserResult, srcFile string, bcFile string) {
|
2017-06-28 23:13:56 +02:00
|
|
|
args := pr.CompileArgs[:]
|
|
|
|
args = append(args, "-emit-llvm", "-c", srcFile, "-o", bcFile)
|
2017-06-30 19:00:25 +02:00
|
|
|
success, err := execCmd(compilerExecName, args, "")
|
|
|
|
if !success {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("Failed to build bitcode file for %s because: %v\n", srcFile, err)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tries to build object file
|
2017-06-30 23:41:30 +02:00
|
|
|
func execCompile(compilerExecName string, pr parserResult, wg *sync.WaitGroup, ok *bool) {
|
2017-06-28 23:13:56 +02:00
|
|
|
defer (*wg).Done()
|
2017-06-30 19:00:25 +02:00
|
|
|
success, err := execCmd(compilerExecName, pr.InputList, "")
|
2017-06-30 21:17:27 +02:00
|
|
|
if !success {
|
2017-07-05 17:14:11 +02:00
|
|
|
LogError("Failed to compile using given arguments: %v\n", err)
|
2017-06-30 23:41:30 +02:00
|
|
|
*ok = false
|
2017-07-01 00:09:30 +02:00
|
|
|
}
|
2017-06-22 21:14:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func getCompilerExecName(compilerName string) string {
|
2017-06-28 23:13:56 +02:00
|
|
|
switch compilerName {
|
|
|
|
case "clang":
|
2017-06-30 19:34:23 +02:00
|
|
|
if LLVMCCName != "" {
|
|
|
|
return filepath.Join(LLVMToolChainBinDir, LLVMCCName)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
2017-06-30 19:34:23 +02:00
|
|
|
return filepath.Join(LLVMToolChainBinDir, compilerName)
|
2017-06-28 23:13:56 +02:00
|
|
|
case "clang++":
|
2017-06-30 19:34:23 +02:00
|
|
|
if LLVMCXXName != "" {
|
|
|
|
return filepath.Join(LLVMToolChainBinDir, LLVMCXXName)
|
2017-06-28 23:13:56 +02:00
|
|
|
}
|
2017-06-30 19:34:23 +02:00
|
|
|
return filepath.Join(LLVMToolChainBinDir, compilerName)
|
2017-06-28 23:13:56 +02:00
|
|
|
default:
|
2017-07-05 17:14:11 +02:00
|
|
|
LogFatal("The compiler %s is not supported by this tool.", compilerName)
|
2017-06-28 23:13:56 +02:00
|
|
|
return ""
|
|
|
|
}
|
2017-06-22 01:34:56 +02:00
|
|
|
}
|