Compiler now uses LLVM-like output filetype names

Remedies #40
This commit is contained in:
Sasha Koshka 2024-03-26 01:52:49 -04:00
parent 6c7fcf6045
commit cad6a0759a
5 changed files with 100 additions and 29 deletions

View File

@ -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 }

View File

@ -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
}

View File

@ -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 {

View File

@ -20,7 +20,7 @@ type Compiler struct {
Output string
Optimization string
Format string
Filetype Filetype
}
func (this *Compiler) bug (err error) error {

67
compiler/filetype.go Normal file
View 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()
}