parent
4ba07a0861
commit
16eca2ec86
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
import "io"
|
import "io"
|
||||||
|
import "fmt"
|
||||||
import "path/filepath"
|
import "path/filepath"
|
||||||
import "git.tebibyte.media/fspl/fspl/cli"
|
import "git.tebibyte.media/fspl/fspl/cli"
|
||||||
import "git.tebibyte.media/fspl/fspl/entity"
|
import "git.tebibyte.media/fspl/fspl/entity"
|
||||||
@ -34,10 +35,17 @@ func main () {
|
|||||||
quiet := cli.NewFlag (
|
quiet := cli.NewFlag (
|
||||||
'q', "quiet",
|
'q', "quiet",
|
||||||
"Don't print warnings, errors, etc.")
|
"Don't print warnings, errors, etc.")
|
||||||
format := cli.NewInputFlag (
|
filetype := cli.NewInputFlag (
|
||||||
'm', "format",
|
't', "filetype",
|
||||||
"Output format (.s, .o, .ll)", "",
|
fmt.Sprintf (
|
||||||
cli.NewValSet(".s", ".o", ".ll"))
|
"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 (
|
output := cli.NewInputFlag (
|
||||||
'o', "output",
|
'o', "output",
|
||||||
"Output filename", "",
|
"Output filename", "",
|
||||||
@ -52,7 +60,7 @@ func main () {
|
|||||||
cli.NewHelp(),
|
cli.NewHelp(),
|
||||||
debug,
|
debug,
|
||||||
quiet,
|
quiet,
|
||||||
format,
|
filetype,
|
||||||
output,
|
output,
|
||||||
optimization)
|
optimization)
|
||||||
|
|
||||||
@ -67,7 +75,7 @@ func main () {
|
|||||||
// configure the compiler based on user input
|
// configure the compiler based on user input
|
||||||
comp.Output = output.Value
|
comp.Output = output.Value
|
||||||
comp.Optimization = optimization.Value
|
comp.Optimization = optimization.Value
|
||||||
comp.Format = format.Value
|
comp.Filetype, _ = compiler.FiletypeFromString(filetype.Value)
|
||||||
comp.Debug = debug.Value != ""
|
comp.Debug = debug.Value != ""
|
||||||
if quiet.Value != "" { comp.Writer = io.Discard }
|
if quiet.Value != "" { comp.Writer = io.Discard }
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ func defaultCompiler () *Compiler {
|
|||||||
"/test-data/usr/local/incude/fspl",
|
"/test-data/usr/local/incude/fspl",
|
||||||
"/test-data/usr/include/fspl")
|
"/test-data/usr/include/fspl")
|
||||||
comp.Resolver.FS = testData
|
comp.Resolver.FS = testData
|
||||||
comp.Format = ".o"
|
comp.Filetype = FiletypeObject
|
||||||
comp.Debug = true
|
comp.Debug = true
|
||||||
return comp
|
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
|
// 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
|
// extension of the input. if that isn't specified, default to .o
|
||||||
if this.Format == "" {
|
if this.Filetype == FiletypeUnknown {
|
||||||
this.Format = filepath.Ext(this.Output)
|
var ok bool
|
||||||
|
this.Filetype, ok = FiletypeFromExt(filepath.Ext(this.Output))
|
||||||
|
if !ok {
|
||||||
|
this.Filetype = FiletypeObject
|
||||||
}
|
}
|
||||||
if this.Format == "" {
|
|
||||||
this.Format = ".o"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the output file is unspecified, generate a nickname from the
|
// 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 == "" {
|
if this.Output == "" {
|
||||||
nickname, ok := address.Nickname()
|
nickname, ok := address.Nickname()
|
||||||
if !ok { nickname = "output" }
|
if !ok { nickname = "output" }
|
||||||
this.Output = nickname + this.Format
|
this.Output = this.Filetype.Extend(nickname)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do something based on the output extension
|
// do something based on the output extension
|
||||||
// TODO: add .so
|
// TODO: add .so
|
||||||
switch this.Format {
|
switch this.Filetype {
|
||||||
case ".s":
|
case FiletypeAssembly, FiletypeObject:
|
||||||
return this.CompileIRModule(irModule, "asm")
|
return this.CompileIRModule(irModule, this.Filetype)
|
||||||
case ".o":
|
case FiletypeIR:
|
||||||
return this.CompileIRModule(irModule, "obj")
|
|
||||||
case ".ll":
|
|
||||||
file, err := os.Create(this.Output)
|
file, err := os.Create(this.Output)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
_, err = irModule.WriteTo(file)
|
_, err = irModule.WriteTo(file)
|
||||||
return err
|
return err
|
||||||
case "":
|
|
||||||
return errors.New(fmt.Sprint (
|
|
||||||
"output file has no extension, ",
|
|
||||||
"could not determine output type"))
|
|
||||||
default:
|
default:
|
||||||
return errors.New(fmt.Sprintf (
|
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)
|
this.Debugln("compiling ir module to filetype", filetype)
|
||||||
|
|
||||||
commandName, args, err := this.FindBackend(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
|
// - llc-<latest> -> llc-14
|
||||||
// - clang
|
// - clang
|
||||||
// If none were found, it returns an error.
|
// 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"
|
optimization := "0"
|
||||||
if this.Optimization != "" { optimization = this.Optimization }
|
if this.Optimization != "" { optimization = this.Optimization }
|
||||||
|
|
||||||
@ -139,8 +134,9 @@ func (this *Compiler) FindBackend (filetype string) (string, []string, error) {
|
|||||||
_, err = exec.LookPath(commandName)
|
_, err = exec.LookPath(commandName)
|
||||||
this.Debugln("trying", commandName)
|
this.Debugln("trying", commandName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if filetype != "obj" {
|
if filetype != FiletypeObject {
|
||||||
return "", nil, errors.New("need 'llc' to compile to " + filetype)
|
return "", nil, errors.New(fmt.Sprint (
|
||||||
|
"need 'llc' to compile to ", filetype))
|
||||||
}
|
}
|
||||||
this.Warnln("falling back to clang to compile llvm ir. expect bugs")
|
this.Warnln("falling back to clang to compile llvm ir. expect bugs")
|
||||||
return commandName, []string {
|
return commandName, []string {
|
||||||
|
@ -20,7 +20,7 @@ type Compiler struct {
|
|||||||
|
|
||||||
Output string
|
Output string
|
||||||
Optimization string
|
Optimization string
|
||||||
Format string
|
Filetype Filetype
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Compiler) bug (err error) error {
|
func (this *Compiler) bug (err error) error {
|
||||||
|
67
compiler/filetype.go
Normal file
67
compiler/filetype.go
Normal file
@ -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…
x
Reference in New Issue
Block a user