From 41cd6a66a631903847fed44f2598dd700cc5b729 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Thu, 18 Jul 2024 17:45:33 +0530 Subject: [PATCH] feat: include build script for compiling and linking against luau --- .vscode/settings.json | 3 +- build/build.go | 93 +++++++++++++++++++++++++++ build/cmd.go | 143 ++++++++++++++++++++++++++++++++++++++++++ internal/lauxlib.go | 2 +- internal/lua.go | 2 +- internal/vector3.go | 2 +- internal/vector4.go | 4 +- 7 files changed, 243 insertions(+), 6 deletions(-) create mode 100644 build/build.go create mode 100644 build/cmd.go diff --git a/.vscode/settings.json b/.vscode/settings.json index bd727de..3ac4cd0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,8 @@ "lua.h": "c", "luaconf.h": "c", "cstdint": "c", - "stdlib.h": "c" + "stdlib.h": "c", + "cmath": "cpp" }, "go.toolsEnvVars": { "CGO_LDFLAGS_ALLOW":".*" diff --git a/build/build.go b/build/build.go new file mode 100644 index 0000000..b565bf6 --- /dev/null +++ b/build/build.go @@ -0,0 +1,93 @@ +package main + +import ( + "fmt" + "os" + "path" + "strings" +) + +const LUAU_VERSION = "0.634" +const ARTIFACT_NAME = "libLuau.VM.a" + +func bail(err error) { + if err != nil { + panic(err) + } +} + +func buildVm(artifactDir string, artifactPath string, cmakeFlags ...string) { + dir, homeDirErr := os.MkdirTemp("", "gluau-build") + bail(homeDirErr) + + defer os.RemoveAll(dir) + + // Clone down the Luau repo and checkout the required tag + Exec("git", "", "clone", "https://github.com/luau-lang/luau.git", dir) + Exec("git", dir, "checkout", LUAU_VERSION) + + // Build the Luau VM using CMake + buildDir := path.Join(dir, "cmake") + bail(os.Mkdir(buildDir, os.ModePerm)) + + defaultCmakeFlags := []string{"..", "-DCMAKE_BUILD_TYPE=RelWithDebInfo", "-DLUAU_EXTERN_C=ON"} + Exec("cmake", buildDir, append(defaultCmakeFlags, cmakeFlags...)...) + Exec("cmake", buildDir, "--build", ".", "--target Luau.VM", "--config", "RelWithDebInfo") + + // Copy the artifact to the artifact directory + artifactFile, artifactErr := os.ReadFile(artifactPath) + bail(artifactErr) + bail(os.WriteFile(path.Join(artifactDir, ARTIFACT_NAME), artifactFile, os.ModePerm)) +} + +func main() { + homeDir, homeDirErr := os.UserHomeDir() + bail(homeDirErr) + + artifactDir := path.Join(homeDir, ".gluau") + artifactPath := path.Join(artifactDir, ARTIFACT_NAME) + + bail(os.MkdirAll(artifactDir, os.ModePerm)) + + // TODO: Args for clean build + args := os.Args[1:] + + goArgs := []string{} + cmakeFlags := []string{} + features := []string{} + + for _, arg := range args { + if arg == "--enable-vector4" { + features = append(features, "LUAU_VECTOR4") + cmakeFlags = append(cmakeFlags, "-DLUAU_VECTOR_SIZE=4") + } else { + goArgs = append(goArgs, arg) + } + } + + if _, err := os.Stat(artifactPath); err == nil { + fmt.Printf("[build] Using existing artifact at %s\n", artifactPath) + } else { + buildVm(artifactDir, artifactPath, cmakeFlags...) + } + + buildArgs := []string{"build"} + if len(features) > 0 { + buildArgs = append(buildArgs, []string{"-tags", strings.Join(features, ",")}...) + } + + cmd, _, _, _ := Command("go"). + WithArgs(append( + buildArgs, goArgs..., + )...). + WithVar( + "CGO_LDFLAGS", + fmt.Sprintf("-L %s -lLuau.VM -lm -lstdc++", artifactDir), + ). + WithVar("CGO_ENABLED", "1"). + PipeAll(Forward). + ToCommand() + + bail(cmd.Start()) + bail(cmd.Wait()) +} diff --git a/build/cmd.go b/build/cmd.go new file mode 100644 index 0000000..072be6e --- /dev/null +++ b/build/cmd.go @@ -0,0 +1,143 @@ +package main + +import ( + "bytes" + "io" + "os" + "os/exec" +) + +type CommandPipeMode int + +const ( + Forward CommandPipeMode = iota + 1 + Consume +) + +type CommandBuilder struct { + cmd string + args []string + env map[string]string + dir string + stdin string + pipeMode struct { + stdin CommandPipeMode + stdout CommandPipeMode + stderr CommandPipeMode + } +} + +func Command(cmd string) CommandBuilder { + return CommandBuilder{cmd: cmd} +} + +func (c CommandBuilder) WithArgs(args ...string) CommandBuilder { + c.args = args + return c +} + +func (c CommandBuilder) WithStdin(stdin string) CommandBuilder { + c.stdin = stdin + return c +} + +func (c CommandBuilder) WithVar(env string, val string) CommandBuilder { + if c.env == nil { + c.env = make(map[string]string) + } + + c.env[env] = val + return c +} + +func (c CommandBuilder) Dir(dir string) CommandBuilder { + c.dir = dir + return c +} + +func (c CommandBuilder) PipeStdin(mode CommandPipeMode) CommandBuilder { + c.pipeMode.stdin = mode + return c +} + +func (c CommandBuilder) PipeStdout(mode CommandPipeMode) CommandBuilder { + c.pipeMode.stdout = mode + return c +} + +func (c CommandBuilder) PipeStderr(mode CommandPipeMode) CommandBuilder { + c.pipeMode.stderr = mode + return c +} + +func (c CommandBuilder) PipeAll(mode CommandPipeMode) CommandBuilder { + c.pipeMode.stdin = mode + c.pipeMode.stdout = mode + c.pipeMode.stderr = mode + return c +} + +func (c CommandBuilder) ToCommand() (exec.Cmd, io.Reader, io.Writer, io.Writer) { + stdinReader := pipeModeToReader(c.pipeMode.stdin, os.Stdin, c.stdin) + stdoutWriter := pipeModeToWriter(c.pipeMode.stdout, os.Stdout) + stderrWriter := pipeModeToWriter(c.pipeMode.stderr, os.Stderr) + + cmdPath, err := exec.LookPath(c.cmd) + if err != nil { + panic(err) + } + + var env []string = os.Environ() + for envVar, val := range c.env { + env = append(env, envVar+"="+val) + } + + cmd := exec.Cmd{ + Path: cmdPath, + Args: append([]string{cmdPath}, c.args...), + Dir: c.dir, + Env: env, + Stdin: stdinReader, + Stdout: stdoutWriter, + Stderr: stderrWriter, + } + + return cmd, stdinReader, stdoutWriter, stderrWriter +} + +func pipeModeToReader(mode CommandPipeMode, def io.Reader, input string) io.Reader { + switch mode { + case Forward: + return def + case Consume: + return bytes.NewReader([]byte(input)) + default: + panic("invalid pipe mode") + } +} + +func pipeModeToWriter(mode CommandPipeMode, def io.Writer) io.Writer { + switch mode { + case Forward: + return def + case Consume: + return bytes.NewBuffer([]byte{}) + default: + panic("invalid pipe mode") + } +} + +func Exec(name string, dir string, args ...string) { + cmd, _, _, _ := Command(name).WithArgs(args...).Dir(dir).PipeAll(Forward).ToCommand() + startErr := cmd.Start() + if startErr != nil { + panic(startErr) + } + + cmdErr := cmd.Wait() + if cmdErr != nil { + panic(cmdErr) + // err := cmdErr.(*exec.ExitError) + // os.Exit(err.ExitCode()) + } +} diff --git a/internal/lauxlib.go b/internal/lauxlib.go index 3a16a85..609ae29 100644 --- a/internal/lauxlib.go +++ b/internal/lauxlib.go @@ -2,7 +2,7 @@ package internal /* #cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -#cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ +// #cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ #include #include #include diff --git a/internal/lua.go b/internal/lua.go index a8e97bd..5e9c91f 100644 --- a/internal/lua.go +++ b/internal/lua.go @@ -2,7 +2,7 @@ package internal /* #cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -#cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ +// #cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ #include #include #include diff --git a/internal/vector3.go b/internal/vector3.go index 5deeb36..6e0d546 100644 --- a/internal/vector3.go +++ b/internal/vector3.go @@ -4,7 +4,7 @@ package internal /* #cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -#cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ +// #cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ #include */ import "C" diff --git a/internal/vector4.go b/internal/vector4.go index ac9a0ff..0dac2b6 100644 --- a/internal/vector4.go +++ b/internal/vector4.go @@ -3,8 +3,8 @@ package internal /* -#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -#cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ +#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -DLUA_VECTOR_SIZE=4 +// #cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++ #include */ import "C"