parent
6c7fcf6045
commit
cad6a0759a
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import "os"
|
||||
import "io"
|
||||
import "fmt"
|
||||
import "path/filepath"
|
||||
import "git.tebibyte.media/fspl/fspl/cli"
|
||||
import "git.tebibyte.media/fspl/fspl/entity"
|
||||
|
@ -34,10 +35,17 @@ func main () {
|
|||
quiet := cli.NewFlag (
|
||||
'q', "quiet",
|
||||
"Don't print warnings, errors, etc.")
|
||||
format := cli.NewInputFlag (
|
||||
'm', "format",
|
||||
"Output format (.s, .o, .ll)", "",
|
||||
cli.NewValSet(".s", ".o", ".ll"))
|
||||
filetype := cli.NewInputFlag (
|
||||
't', "filetype",
|
||||
fmt.Sprintf (
|
||||
"Output format (%s, %s, %s)",
|
||||
compiler.FiletypeAssembly,
|
||||
compiler.FiletypeObject,
|
||||
compiler.FiletypeIR), "",
|
||||
cli.NewValSet (
|
||||
compiler.FiletypeAssembly.String(),
|
||||
compiler.FiletypeObject.String(),
|
||||
compiler.FiletypeIR.String()))
|
||||
output := cli.NewInputFlag (
|
||||
'o', "output",
|
||||
"Output filename", "",
|
||||
|
@ -52,7 +60,7 @@ func main () {
|
|||
cli.NewHelp(),
|
||||
debug,
|
||||
quiet,
|
||||
format,
|
||||
filetype,
|
||||
output,
|
||||
optimization)
|
||||
|
||||
|
@ -67,7 +75,7 @@ func main () {
|
|||
// configure the compiler based on user input
|
||||
comp.Output = output.Value
|
||||
comp.Optimization = optimization.Value
|
||||
comp.Format = format.Value
|
||||
comp.Filetype, _ = compiler.FiletypeFromString(filetype.Value)
|
||||
comp.Debug = debug.Value != ""
|
||||
if quiet.Value != "" { comp.Writer = io.Discard }
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ func defaultCompiler () *Compiler {
|
|||
"/test-data/usr/local/incude/fspl",
|
||||
"/test-data/usr/include/fspl")
|
||||
comp.Resolver.FS = testData
|
||||
comp.Format = ".o"
|
||||
comp.Filetype = FiletypeObject
|
||||
comp.Debug = true
|
||||
return comp
|
||||
}
|
||||
|
|
|
@ -29,11 +29,12 @@ func (this *Compiler) CompileUnit (address entity.Address) error {
|
|||
|
||||
// if the format isn't specified, try to get it from the filename
|
||||
// extension of the input. if that isn't specified, default to .o
|
||||
if this.Format == "" {
|
||||
this.Format = filepath.Ext(this.Output)
|
||||
}
|
||||
if this.Format == "" {
|
||||
this.Format = ".o"
|
||||
if this.Filetype == FiletypeUnknown {
|
||||
var ok bool
|
||||
this.Filetype, ok = FiletypeFromExt(filepath.Ext(this.Output))
|
||||
if !ok {
|
||||
this.Filetype = FiletypeObject
|
||||
}
|
||||
}
|
||||
|
||||
// if the output file is unspecified, generate a nickname from the
|
||||
|
@ -41,32 +42,26 @@ func (this *Compiler) CompileUnit (address entity.Address) error {
|
|||
if this.Output == "" {
|
||||
nickname, ok := address.Nickname()
|
||||
if !ok { nickname = "output" }
|
||||
this.Output = nickname + this.Format
|
||||
this.Output = this.Filetype.Extend(nickname)
|
||||
}
|
||||
|
||||
// do something based on the output extension
|
||||
// TODO: add .so
|
||||
switch this.Format {
|
||||
case ".s":
|
||||
return this.CompileIRModule(irModule, "asm")
|
||||
case ".o":
|
||||
return this.CompileIRModule(irModule, "obj")
|
||||
case ".ll":
|
||||
switch this.Filetype {
|
||||
case FiletypeAssembly, FiletypeObject:
|
||||
return this.CompileIRModule(irModule, this.Filetype)
|
||||
case FiletypeIR:
|
||||
file, err := os.Create(this.Output)
|
||||
if err != nil { return err }
|
||||
defer file.Close()
|
||||
_, err = irModule.WriteTo(file)
|
||||
return err
|
||||
case "":
|
||||
return errors.New(fmt.Sprint (
|
||||
"output file has no extension, ",
|
||||
"could not determine output type"))
|
||||
default:
|
||||
return errors.New(fmt.Sprintf (
|
||||
"unknown output type %s", this.Format))
|
||||
"unknown output type %s", this.Filetype))
|
||||
}
|
||||
}
|
||||
func (this *Compiler) CompileIRModule (module *llvm.Module, filetype string) error {
|
||||
func (this *Compiler) CompileIRModule (module *llvm.Module, filetype Filetype) error {
|
||||
this.Debugln("compiling ir module to filetype", filetype)
|
||||
|
||||
commandName, args, err := this.FindBackend(filetype)
|
||||
|
@ -93,7 +88,7 @@ func (this *Compiler) CompileIRModule (module *llvm.Module, filetype string) err
|
|||
// - llc-<latest> -> llc-14
|
||||
// - clang
|
||||
// If none were found, it returns an error.
|
||||
func (this *Compiler) FindBackend (filetype string) (string, []string, error) {
|
||||
func (this *Compiler) FindBackend (filetype Filetype) (string, []string, error) {
|
||||
optimization := "0"
|
||||
if this.Optimization != "" { optimization = this.Optimization }
|
||||
|
||||
|
@ -139,8 +134,9 @@ func (this *Compiler) FindBackend (filetype string) (string, []string, error) {
|
|||
_, err = exec.LookPath(commandName)
|
||||
this.Debugln("trying", commandName)
|
||||
if err == nil {
|
||||
if filetype != "obj" {
|
||||
return "", nil, errors.New("need 'llc' to compile to " + filetype)
|
||||
if filetype != FiletypeObject {
|
||||
return "", nil, errors.New(fmt.Sprint (
|
||||
"need 'llc' to compile to ", filetype))
|
||||
}
|
||||
this.Warnln("falling back to clang to compile llvm ir. expect bugs")
|
||||
return commandName, []string {
|
||||
|
|
|
@ -20,7 +20,7 @@ type Compiler struct {
|
|||
|
||||
Output string
|
||||
Optimization string
|
||||
Format string
|
||||
Filetype Filetype
|
||||
}
|
||||
|
||||
func (this *Compiler) bug (err error) error {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package compiler
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Filetype represents an output filetype.
|
||||
type Filetype int; const (
|
||||
FiletypeUnknown Filetype = iota
|
||||
FiletypeObject
|
||||
FiletypeLibrary
|
||||
FiletypeAssembly
|
||||
FiletypeIR
|
||||
)
|
||||
|
||||
// FiletypeFromString returns a filetype based on the given name.
|
||||
func FiletypeFromString (ext string) (Filetype, bool) {
|
||||
switch ext {
|
||||
case "": return FiletypeUnknown, true
|
||||
case "obj": return FiletypeObject, true
|
||||
case "lib": return FiletypeLibrary, true
|
||||
case "asm": return FiletypeAssembly, true
|
||||
case "ir": return FiletypeIR, true
|
||||
default: return FiletypeUnknown, false
|
||||
}
|
||||
}
|
||||
|
||||
// FiletypeFromExt returns a filetype based on the given filename extension.
|
||||
func FiletypeFromExt (ext string) (Filetype, bool) {
|
||||
// FIXME some of these are platform dependent, for example on windows
|
||||
// FiletypeLib would be .dll
|
||||
switch ext {
|
||||
case ".o": return FiletypeObject, true
|
||||
case ".so": return FiletypeLibrary, true
|
||||
case ".s": return FiletypeAssembly, true
|
||||
case ".ll": return FiletypeIR, true
|
||||
default: return FiletypeUnknown, false
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of the filetype.
|
||||
func (filetype Filetype) String () string {
|
||||
switch filetype {
|
||||
case FiletypeUnknown: return ""
|
||||
case FiletypeObject: return "obj"
|
||||
case FiletypeLibrary: return "lib"
|
||||
case FiletypeAssembly: return "asm"
|
||||
case FiletypeIR: return "ir"
|
||||
default: return fmt.Sprintf("Filetype(%d)", filetype)
|
||||
}
|
||||
}
|
||||
|
||||
// Ext returns the standard filename extension of the filetype.
|
||||
func (filetype Filetype) Ext () string {
|
||||
// FIXME again, some of these are platform dependent
|
||||
switch filetype {
|
||||
case FiletypeUnknown: return ""
|
||||
case FiletypeObject: return ".o"
|
||||
case FiletypeLibrary: return ".so"
|
||||
case FiletypeAssembly: return ".s"
|
||||
case FiletypeIR: return ".ll"
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Extend adds the extension of the filetype onto the specified path.
|
||||
func (filetype Filetype) Extend (path string) string {
|
||||
return path + filetype.Ext()
|
||||
}
|
Loading…
Reference in New Issue