From 865520b571da6ee3cf7e3676c9bb599f70c4c321 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 12 Sep 2018 19:56:15 +0200 Subject: [PATCH] compiler: act as a compiler driver (on unix systems) As a final step, link the object file with the system compiler/linker. TODO: cross compiling. --- compiler.go | 2 +- main.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/compiler.go b/compiler.go index 0cedbb4c..1d69a4ce 100644 --- a/compiler.go +++ b/compiler.go @@ -92,7 +92,7 @@ func NewCompiler(pkgName, triple string, dumpSSA bool) (*Compiler, error) { if err != nil { return nil, err } - c.machine = target.CreateTargetMachine(triple, "", "", llvm.CodeGenLevelDefault, llvm.RelocDefault, llvm.CodeModelDefault) + c.machine = target.CreateTargetMachine(triple, "", "", llvm.CodeGenLevelDefault, llvm.RelocPIC, llvm.CodeModelDefault) c.targetData = c.machine.CreateTargetData() c.mod = llvm.NewModule(pkgName) diff --git a/main.go b/main.go index 7f1ed5b0..84fdd16c 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,11 @@ import ( "errors" "flag" "fmt" + "io" + "io/ioutil" "os" + "os/exec" + "path/filepath" "runtime" "strings" @@ -67,7 +71,56 @@ func Compile(pkgName, runtimePath, outpath, target string, printIR, dumpSSA bool } else if strings.HasSuffix(outpath, ".ll") { return c.EmitText(outpath) } else { - return errors.New("unknown output file extension") + // Act as a compiler driver. + + // Create a temporary directory for intermediary files. + dir, err := ioutil.TempDir("", "tinygo") + if err != nil { + return err + } + defer os.RemoveAll(dir) + + // Write the object file. + objfile := filepath.Join(dir, "main.o") + err = c.EmitObject(objfile) + if err != nil { + return err + } + + // Link the object file with the system compiler. + executable := filepath.Join(dir, "main") + cmd := exec.Command("cc", "-o", executable, objfile) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + if err != nil { + return err + } + + if err := os.Rename(executable, outpath); err != nil { + // Moving failed. Do a file copy. + inf, err := os.Open(executable) + if err != nil { + return err + } + defer inf.Close() + outf, err := os.OpenFile(outpath, os.O_RDWR|os.O_CREATE, 0777) + if err != nil { + return err + } + + // Copy data to output file. + _, err = io.Copy(outf, inf) + if err != nil { + return err + } + + // Check whether file writing was successful. + return outf.Close() + } else { + // Move was successful. + return nil + } } }