[WIP] implement compiling part

This commit is contained in:
Loic Gelle 2017-06-22 12:14:00 -07:00
parent 3f332fd60b
commit e14e7e328c
4 changed files with 173 additions and 13 deletions

View File

@ -1,19 +1,149 @@
package main
import (
"fmt"
"os"
"os/exec"
"log"
"strings"
)
func compile(args []string) {
if len(args) < 1 {
fmt.Println("You must precise which compiler to use.")
os.Exit(1)
log.Fatal("You must precise which compiler to use.")
}
var compilerName = args[0]
var compilerExecName = getCompilerExecName(compilerName)
var configureOnly bool
if os.Getenv(CONFIGURE_ONLY) != "" {
configureOnly = true
}
args = args[1:]
var pr = parse(args)
var _ = pr
var _ = compilerName
// If configure only is set, try to execute normal compiling command then exit silently
if configureOnly {
execCompile(compilerExecName, pr)
os.Exit(0)
}
// Else try to build objects and bitcode
buildAndAttachBitcode(compilerExecName, pr)
}
// Compiles bitcode files and attach path to the object files
func buildAndAttachBitcode(compilerExecName string, pr ParserResult) {
// If nothing to do, exit silently
if len(pr.InputFiles) == 0 || pr.IsEmitLLVM || pr.IsAssembly || pr.IsAssembleOnly ||
(pr.IsDependencyOnly && !pr.IsCompileOnly) || pr.IsPreprocessOnly {
os.Exit(0)
}
var newObjectFiles []string
var hidden = !pr.IsCompileOnly
if len(pr.InputFiles) == 1 && pr.IsCompileOnly {
var srcFile = pr.InputFiles[0]
objFile, bcFile := getArtifactNames(pr, 0, hidden)
buildObjectFile(compilerExecName, pr, srcFile, objFile)
buildBitcodeFile(compilerExecName, pr, srcFile, bcFile)
attachBitcodePathToObject(bcFile, objFile)
} else {
for i, srcFile := range pr.InputFiles {
objFile, bcFile := getArtifactNames(pr, i, hidden)
buildObjectFile(compilerExecName, pr, srcFile, objFile)
if hidden {
newObjectFiles = append(newObjectFiles, objFile)
} else if strings.HasSuffix(srcFile, ".bc") {
attachBitcodePathToObject(srcFile, objFile)
} else {
buildBitcodeFile(compilerExecName, pr, srcFile, bcFile)
attachBitcodePathToObject(bcFile, objFile)
}
}
}
if !pr.IsCompileOnly {
linkFiles(compilerExecName, pr, newObjectFiles)
}
}
func attachBitcodePathToObject(bcFile, objFile string) {
// TODO
}
func linkFiles(compilerExecName string, pr ParserResult, objFiles []string) {
var outputFile = pr.OutputFilename
if outputFile == "" {
outputFile = "a.out"
}
args := append(pr.ObjectFiles, objFiles...)
args = append(args, pr.LinkArgs...)
args = append(args, "-o", outputFile)
if execCmd(compilerExecName, args) {
log.Fatal("Failed to link.")
}
}
// Tries to build the specified source file to object
func buildObjectFile(compilerExecName string, pr ParserResult, srcFile string, objFile string) {
args := pr.CompileArgs[:]
args = append(args, srcFile, "-c", "-o", objFile)
if execCmd(compilerExecName, args) {
log.Fatal("Failed to build object file for", srcFile)
}
}
// Tries to build the specified source file to bitcode
func buildBitcodeFile(compilerExecName string, pr ParserResult, srcFile string, bcFile string) {
args := pr.CompileArgs[:]
args = append(args, "-emit-llvm", "-c", srcFile, "-o", bcFile)
if execCmd(compilerExecName, args) {
log.Fatal("Failed to build bitcode file for", srcFile)
}
}
// Tries to build object file
func execCompile(compilerExecName string, pr ParserResult) {
if execCmd(compilerExecName, pr.InputList) {
log.Fatal("Failed to execute compile command.")
}
}
// Executes a command then returns true if there was an error
func execCmd(cmdExecName string, args []string) bool {
cmd := exec.Command(cmdExecName, listToArgString(args))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if cmd.Run() == nil {
return false
} else {
return true
}
}
// Joins a list of arguments to create a string
func listToArgString(argList []string) string {
return strings.Join(argList, " ")
}
func getCompilerExecName(compilerName string) string {
var compilerPath = os.Getenv(COMPILER_PATH)
switch compilerName {
case "clang":
var clangName = os.Getenv(C_COMPILER_NAME)
if clangName != "" {
return compilerPath + clangName
} else {
return compilerPath + compilerName
}
case "clang++":
var clangppName = os.Getenv(C_COMPILER_NAME)
if clangppName != "" {
return compilerPath + clangppName
} else {
return compilerPath + compilerName
}
default:
log.Fatal("The compiler", compilerName, "is not supported by this tool.")
return ""
}
}

View File

@ -1 +1,13 @@
package main
// Environment variables
var CONFIGURE_ONLY = "GOWLLVM_CONFIGURE_ONLY"
var COMPILER_PATH = "GOWLLVM_COMPILER_PATH"
var C_COMPILER_NAME = "GOWLLVM_CC_NAME"
var CXX_COMPILER_NAME = "GOWLLVM_CXX_NAME"
var BC_STORE_PATH = "GOWLLVM_BC_STORE"
// Gowllvm functioning
var ELF_SECTION_NAME = ".llvm_bc"
var DARWIN_SEGMENT_NAME = "__WLLVM"
var DARWIN_SECTION_NAME = "__llvm_bc"

View File

@ -1,16 +1,15 @@
package main
import(
"fmt"
"os"
"log"
)
func main() {
// Parse command line
var args = os.Args
if len(args) < 2 {
fmt.Println("Not enough arguments.")
os.Exit(1)
log.Fatal("Not enough arguments.")
}
var modeFlag = args[1]
args = args[2:]
@ -20,10 +19,8 @@ func main() {
// Call main compile function with args
compile(args)
case "extract":
fmt.Println("The extract feature is not implemented yet.")
os.Exit(1)
log.Fatal("The extract feature is not implemented yet.")
default:
fmt.Println("You should call gowllvm with a valid mode.")
os.Exit(1)
log.Fatal("You should call gowllvm with a valid mode.")
}
}

View File

@ -4,6 +4,8 @@ import(
"fmt"
"regexp"
"runtime"
"path/filepath"
"strings"
)
type ParserResult struct {
@ -215,6 +217,25 @@ func parse(argList []string) ParserResult {
return pr
}
// Return the object and bc filenames that correspond to the i-th source file
func getArtifactNames(pr ParserResult, srcFileIndex int, hidden bool) (objBase string, bcBase string) {
if len(pr.InputFiles) == 1 && pr.IsCompileOnly && len(pr.OutputFilename) > 0 {
objBase = pr.OutputFilename
bcBase = fmt.Sprintf(".%s.bc", objBase)
} else {
srcFile := pr.InputFiles[srcFileIndex]
var baseNameWithExt = filepath.Base(srcFile)
var baseName = strings.TrimSuffix(baseNameWithExt, filepath.Ext(baseNameWithExt))
bcBase = fmt.Sprintf(".%s.o.bc", baseName)
if hidden {
objBase = fmt.Sprintf(".%s.o", baseName)
} else {
objBase = fmt.Sprintf("%s.o", baseName)
}
}
return
}
func inputFileCallback(pr ParserResult, flag string, _ []string) {
var regExp = regexp.MustCompile(`\\.(s|S)$`)
pr.InputFiles = append(pr.InputFiles, flag)