Skip to content

Commit

Permalink
CORE: Add windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
MineGame159 committed Feb 7, 2024
1 parent 56e58a9 commit 3418ba0
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ example/build
tests/build

/fireball
/fireball.exe
18 changes: 10 additions & 8 deletions cmd/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func Build(project *workspace.Project, entrypoint *ir.Module, optimizationLevel
irPaths := make([]string, 0, len(project.Files))

for _, file := range project.Files {
path := strings.ReplaceAll(file.Path, "/", "-")
path := strings.ReplaceAll(file.Path, string(os.PathSeparator), "-")
path = filepath.Join(project.Path, "build", path[:len(path)-3]+".ll")

irFile, err := os.Create(path)
Expand Down Expand Up @@ -56,18 +56,12 @@ func Build(project *workspace.Project, entrypoint *ir.Module, optimizationLevel
c.AddInput(irPath)
}

if runtime.GOOS == "darwin" {
c.AddLibrary("System")
} else {
c.AddLibrary("m")
c.AddLibrary("c")
}

for _, library := range project.Config.LinkLibraries {
c.AddLibrary(library)
}

output := filepath.Join(project.Path, "build", outputName)
output = withExecutableExtension(output)

err = c.Compile(output)
if err != nil {
Expand All @@ -76,3 +70,11 @@ func Build(project *workspace.Project, entrypoint *ir.Module, optimizationLevel

return output, nil
}

func withExecutableExtension(path string) string {
if runtime.GOOS == "windows" {
return path + ".exe"
}

return path
}
49 changes: 10 additions & 39 deletions cmd/build/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"os/exec"
"path/filepath"
"runtime"
"strings"
)

Expand Down Expand Up @@ -101,49 +100,33 @@ func (c *Compiler) compileIr(input string) error {
return execute(cmd)
}

//goland:noinspection GoBoolExpressions
func (c *Compiler) linkExecutable(inputs []string, output string) error {
// Create command
cmd := exec.Command(getLinker(), "-L/usr/lib")

switch runtime.GOOS {
case "linux":
cmd.Args = append(cmd.Args, "-dynamic-linker")
cmd.Args = append(cmd.Args, "/lib64/ld-linux-x86-64.so.2")

cmd.Args = append(cmd.Args, "/usr/lib/crt1.o")
cmd.Args = append(cmd.Args, "/usr/lib/crti.o")
l := GetLinker()

case "darwin":
cmd.Args = append(cmd.Args, "-dynamic")
cmd.Args = append(cmd.Args, "-syslibroot")
cmd.Args = append(cmd.Args, "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
err := l.Check()
if err != nil {
return err
}

for _, library := range c.libraries {
cmd.Args = append(cmd.Args, "-l"+library)
l.AddLibrary(library)
}

for _, input := range inputs {
cmd.Args = append(cmd.Args, withExtension(input, "o"))
l.AddInput(withExtension(input, "o"))
}

if runtime.GOOS == "linux" {
cmd.Args = append(cmd.Args, "/usr/lib/crtn.o")
}

cmd.Args = append(cmd.Args, "-o")
cmd.Args = append(cmd.Args, output)

// Execute
return execute(cmd)
return l.Link(output)
}

func execute(cmd *exec.Cmd) error {
stderr := bytes.Buffer{}
cmd.Stderr = &stderr

err := cmd.Run()
if err != nil {
return errors.New(err.Error() + " : " + stderr.String())
}

if !cmd.ProcessState.Success() {
return errors.New(stderr.String())
Expand All @@ -152,18 +135,6 @@ func execute(cmd *exec.Cmd) error {
return err
}

func getLinker() string {
switch runtime.GOOS {
case "linux":
return "ld.lld"
case "darwin":
return "ld"

default:
panic("Unknown operating system: " + runtime.GOOS)
}
}

func withExtension(path, extension string) string {
dot := strings.LastIndexByte(path, '.')
return path[:dot+1] + extension
Expand Down
24 changes: 24 additions & 0 deletions cmd/build/linker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package build

import "runtime"

type Linker interface {
Check() error

AddLibrary(library string)
AddInput(input string)

Link(output string) error
}

func GetLinker() Linker {
switch runtime.GOOS {
case "windows":
return &windowsLinker{}
case "linux":
return &linuxLinker{}

default:
panic("Operating system not implemented")
}
}
52 changes: 52 additions & 0 deletions cmd/build/linux_linker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package build

import (
"os/exec"
)

type linuxLinker struct {
libraries []string
inputs []string
}

func (l *linuxLinker) Check() error {
l.libraries = append(l.libraries, "c")
l.libraries = append(l.libraries, "m")

return nil
}

func (l *linuxLinker) AddLibrary(library string) {
l.libraries = append(l.libraries, library)
}

func (l *linuxLinker) AddInput(input string) {
l.inputs = append(l.inputs, input)
}

func (l *linuxLinker) Link(output string) error {
cmd := exec.Command("ld.lld")

cmd.Args = append(cmd.Args, "-L/usr/lib")

cmd.Args = append(cmd.Args, "-dynamic-linker")
cmd.Args = append(cmd.Args, "/lib64/ld-linux-x86-64.so.2")

cmd.Args = append(cmd.Args, "/usr/lib/crt1.o")
cmd.Args = append(cmd.Args, "/usr/lib/crti.o")

for _, library := range l.libraries {
cmd.Args = append(cmd.Args, "-l"+library)
}

for _, input := range l.inputs {
cmd.Args = append(cmd.Args, withExtension(input, "o"))
}

cmd.Args = append(cmd.Args, "/usr/lib/crtn.o")

cmd.Args = append(cmd.Args, "-o")
cmd.Args = append(cmd.Args, output)

return execute(cmd)
}
103 changes: 103 additions & 0 deletions cmd/build/windows_linker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package build

import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
)

type windowsLinker struct {
ucrtPath string
umPath string
msvcPath string

libraries []string
inputs []string
}

func (w *windowsLinker) Check() error {
if err := w.findKit(); err != nil {
return err
}
if err := w.findMsvc(); err != nil {
return err
}

w.libraries = append(w.libraries, "libucrt.lib")
w.libraries = append(w.libraries, "libcmt.lib")

return nil
}

func (w *windowsLinker) findKit() error {
base := "C:\\Program Files (x86)\\Windows Kits\\10\\Lib"

entries, err := os.ReadDir(base)
if err != nil {
return errors.New("failed to find a valid windows development kit")
}

w.ucrtPath = filepath.Join(base, entries[0].Name(), "ucrt", "x64")
_, err = os.Stat(w.ucrtPath)
if err != nil {
return errors.New("failed to find a valid windows development kit, ucrt")
}

w.umPath = filepath.Join(base, entries[0].Name(), "um", "x64")
_, err = os.Stat(w.umPath)
if err != nil {
return errors.New("failed to find a valid windows development kit, um")
}

return nil
}

func (w *windowsLinker) findMsvc() error {
base := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Tools\\MSVC"

entries, err := os.ReadDir(base)
if err != nil {
return errors.New("failed to find a MSVC installation")
}

w.msvcPath = filepath.Join(base, entries[0].Name(), "lib", "x64")
_, err = os.Stat(w.msvcPath)
if err != nil {
return errors.New("failed to find a MSVC installation, lib")
}

return nil
}

func (w *windowsLinker) AddLibrary(library string) {
w.libraries = append(w.libraries, library)
}

func (w *windowsLinker) AddInput(input string) {
w.inputs = append(w.inputs, input)
}

func (w *windowsLinker) Link(output string) error {
cmd := exec.Command("lld-link")

cmd.Args = append(cmd.Args, fmt.Sprintf("/libpath:%s", w.ucrtPath))
cmd.Args = append(cmd.Args, fmt.Sprintf("/libpath:%s", w.umPath))
cmd.Args = append(cmd.Args, fmt.Sprintf("/libpath:%s", w.msvcPath))

for _, library := range w.libraries {
cmd.Args = append(cmd.Args, library)
}

for _, input := range w.inputs {
cmd.Args = append(cmd.Args, fmt.Sprintf("%s", input))
}

cmd.Args = append(cmd.Args, "/machine:x64")
cmd.Args = append(cmd.Args, "/subsystem:console")
cmd.Args = append(cmd.Args, "/debug")
cmd.Args = append(cmd.Args, fmt.Sprintf("/out:%s", output))

return execute(cmd)
}
2 changes: 2 additions & 0 deletions core/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Abi interface {

func GetTargetAbi() Abi {
switch runtime.GOOS {
case "windows":
return WIN64
case "linux", "darwin":
return AMD64

Expand Down
Loading

0 comments on commit 3418ba0

Please sign in to comment.