Compare commits

...

7 commits

Author SHA1 Message Date
749c2ae39d
build: remove redundant not nil check for error 2025-04-26 08:57:18 +01:00
fb8d0c1514
build: make build script more ergonomic
* Moved cloning functionality into its own `cloneSrc` function
* Start writing compiled data into CWD instead of user home dir, in
  order to prevent mangling between projects
* Introduce `LEI_LUAU_SRC` variable to allow users to provide a path to
  an already checked out luau source dir; when not set, a temporary
  directory is created and removed after compilation
* Do not panic if cmake build dir already exists, just skip creating in
  that case
* Automatically set required C includes path for commands
* Added warning to commands if the `.lei` directory is not present in
  the gitignore
2025-04-26 08:50:50 +01:00
d82a23b44c
refactor: rename package internal->ffi & fix compile err
Fixed a compile error to do with passing too many arguments to
`lua_setuserdatametatable` when it only accepts 2.
2025-04-26 08:49:43 +01:00
725efd14f8
refactor: export raw bindings as ffi package 2025-04-26 07:51:49 +01:00
08e1de819f
fix: luau does not export a luaL_errorL, write our own 2025-04-26 07:49:28 +01:00
342c56b4da
chore(pkg): update deps 2025-04-26 07:49:08 +01:00
516d7a4f76
build: fix panics for initial runs and remove def exports 2025-04-26 07:48:36 +01:00
16 changed files with 85 additions and 121 deletions

3
.gitignore vendored
View file

@ -17,5 +17,8 @@
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
# Build script compiled data
.lei/
# Dependency directories (remove the comment below to include it)
# vendor/

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "internal/luau"]
path = internal/luau
url = https://github.com/luau-lang/luau
[submodule "ffi/luau"]
path = ffi/luau
url = https://github.com/luau-lang/luau.git

View file

@ -19,27 +19,31 @@ func bail(err error) {
}
}
func buildVm(artifactPath string, cmakeFlags ...string) {
func cloneSrc() string {
color.Blue.Println("> Cloning luau-lang/luau")
dir, homeDirErr := os.MkdirTemp("", "lei-build")
bail(homeDirErr)
defer os.RemoveAll(dir)
dir, tempDirErr := os.MkdirTemp("", "lei-build")
bail(tempDirErr)
// 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)
color.Green.Printf("> Cloned repo to%s\n\n", dir)
return dir
}
func buildVm(srcPath string, artifactPath string, includesDir string, cmakeFlags ...string) {
color.Blue.Println("> Compile libLuau.VM.a")
// Build the Luau VM using CMake
buildDir := path.Join(dir, "cmake")
bail(os.Mkdir(buildDir, os.ModePerm))
buildDir := path.Join(srcPath, "cmake")
buildDirErr := os.Mkdir(buildDir, os.ModePerm)
if !os.IsExist(buildDirErr) {
bail(buildDirErr)
}
defaultCmakeFlags := []string{"..", "-DCMAKE_BUILD_TYPE=RelWithDebInfo", "-DLUAU_EXTERN_C=ON"}
defaultCmakeFlags := []string{"..", "-DCMAKE_BUILD_TYPE=RelWithDebInfo", "-DLUAU_EXTERN_C=ON", "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"}
Exec("cmake", buildDir, append(defaultCmakeFlags, cmakeFlags...)...)
Exec("cmake", buildDir, "--build", ".", "--target Luau.VM", "--config", "RelWithDebInfo")
@ -49,17 +53,37 @@ func buildVm(artifactPath string, cmakeFlags ...string) {
artifactFile, artifactErr := os.ReadFile(path.Join(buildDir, ARTIFACT_NAME))
bail(artifactErr)
bail(os.WriteFile(artifactPath, artifactFile, os.ModePerm))
// Copy the header files into the includes directory
headerDir := path.Join(srcPath, "VM", "include")
headerFiles, headerErr := os.ReadDir(headerDir)
bail(headerErr)
for _, file := range headerFiles {
src := path.Join(headerDir, file.Name())
dest := path.Join(includesDir, file.Name())
headerContents, headerReadErr := os.ReadFile(src)
bail(headerReadErr)
os.WriteFile(dest, headerContents, os.ModePerm)
}
}
func main() {
homeDir, homeDirErr := os.UserHomeDir()
bail(homeDirErr)
workDir, workDirErr := os.Getwd()
bail(workDirErr)
artifactDir := path.Join(homeDir, ".lei")
artifactDir := path.Join(workDir, ".lei")
artifactPath := path.Join(artifactDir, ARTIFACT_NAME)
lockfilePath := path.Join(artifactDir, ".lock")
includesDir := path.Join(artifactDir, "includes")
bail(os.MkdirAll(artifactDir, os.ModePerm))
bail(os.MkdirAll(includesDir, os.ModePerm)) // includesDir is the deepest dir, creates all
gitignore, gitignoreErr := os.ReadFile(".gitignore")
if gitignoreErr == nil && !strings.Contains(string(gitignore), ".lei") {
color.Yellow.Println("> WARN: The gitignore in the CWD does not include `.lei`, consider adding it")
}
// TODO: Args for clean build
args := os.Args[1:]
@ -68,25 +92,35 @@ func main() {
cmakeFlags := []string{}
features := []string{}
// TODO: maybe use env vars for this config instead
for _, arg := range args {
if arg == "--enable-vector4" {
features = append(features, "LUAU_VECTOR4")
// FIXME: This flag apparently isn't recognized by cmake for some reason
cmakeFlags = append(cmakeFlags, "-DLUAU_VECTOR_SIZE=4")
} else {
goArgs = append(goArgs, arg)
}
}
lockfileContents, err := os.ReadFile(lockfilePath)
bail(err)
if !os.IsNotExist(err) {
bail(err)
}
serFeatures := fmt.Sprintf("%v", features)
toCleanBuild := string(lockfileContents) != serFeatures
toCleanBuild := (string(lockfileContents) != serFeatures) || os.Getenv("LEI_CLEAN_BUILD") == "true"
if _, err := os.Stat(artifactPath); err == nil && !toCleanBuild {
fmt.Printf("[build] Using existing artifact at %s\n", artifactPath)
} else {
buildVm(artifactPath, cmakeFlags...)
srcPath, notUnset := os.LookupEnv("LEI_LUAU_SRC")
if !notUnset {
srcPath = cloneSrc()
defer os.RemoveAll(srcPath)
}
buildVm(srcPath, artifactPath, includesDir, cmakeFlags...)
bail(os.WriteFile(lockfilePath, []byte(serFeatures), os.ModePerm))
}
@ -108,6 +142,7 @@ func main() {
"CGO_LDFLAGS",
fmt.Sprintf("-L %s -lLuau.VM -lm -lstdc++", artifactDir),
).
WithVar("CGO_CFLAGS", fmt.Sprintf("-I%s", includesDir)).
WithVar("CGO_ENABLED", "1").
PipeAll(Forward).
ToCommand()

View file

@ -13,11 +13,6 @@ lua_State* clua_newstate(void* f, void* ud)
return lua_newstate((lua_Alloc)f, ud);
}
l_noret cluaL_errorL(lua_State* L, char* msg)
{
luaL_errorL(L, msg);
}
void clua_pushcclosurek(lua_State* L, void* f, char* debugname, int nup, void* cont) {
return lua_pushcclosurek(L, (lua_CFunction)f, debugname, nup, (lua_Continuation)cont);
}

View file

@ -1,4 +1,4 @@
package internal
package ffi
/*
#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include
@ -171,8 +171,10 @@ func LErrorL(L *LuaState, msg string) {
cmsg := C.CString(msg)
defer C.free(unsafe.Pointer(cmsg))
C.cluaL_errorL(L, cmsg)
panic(msg)
PushString(L, msg)
Error(L)
// TODO: do we panic on the go side?
}
func LCheckOption(L *LuaState, narg int32, def string, lst []string) int32 {

View file

@ -1,4 +1,4 @@
package internal
package ffi
/*
#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include
@ -697,7 +697,7 @@ func GetUserdataDtor(L *LuaState, tag int32) LuaDestructor {
}
func SetUserdataMetatable(L *LuaState, tag int32, idx int32) {
C.lua_setuserdatametatable(L, C.int(tag), C.int(idx))
C.lua_setuserdatametatable(L, C.int(idx))
}
func GetUserdataMetatable(L *LuaState, tag int32) {

1
ffi/luau Submodule

@ -0,0 +1 @@
Subproject commit c51743268bcbe5c5af1bd78bcacaefe7f6fe3391

View file

@ -1,4 +1,4 @@
package internal
package ffi
//#include <stdlib.h>
import "C"

View file

@ -1,6 +1,6 @@
//go:build !LUAU_VECTOR4
package internal
package ffi
/*
#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include

11
go.mod
View file

@ -1,3 +1,12 @@
module github.com/CompeyDev/lei
go 1.19
go 1.23.0
toolchain go1.24.2
require (
github.com/gookit/color v1.5.4 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/term v0.31.0 // indirect
)

8
go.sum Normal file
View file

@ -0,0 +1,8 @@
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=

View file

@ -1,91 +0,0 @@
/* Code generated by cmd/cgo; DO NOT EDIT. */
/* package internal */
#line 1 "cgo-builtin-export-prolog"
#include <stddef.h>
#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H
#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
#endif
#endif
/* Start of preamble from import "C" comments. */
#line 3 "lua.go"
// #cgo LDFLAGS: -L${SRCDIR}/luau/cmake -lLuau.VM -lm -lstdc++
#include "/home/compey/dev/gluau/internal/luau/VM/include/lua.h"
#include "/home/compey/dev/gluau/internal/luau/VM/include/lualib.h"
#include <stdlib.h>
#include "/home/compey/dev/gluau/internal/clua.h"
#line 1 "cgo-generated-wrapper"
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
#line 1 "cgo-gcc-export-header-prolog"
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef size_t GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
#ifdef _MSC_VER
#include <complex.h>
typedef _Fcomplex GoComplex64;
typedef _Dcomplex GoComplex128;
#else
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
#endif
/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef _GoString_ GoString;
#endif
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C" {
#endif
extern GoUintptr go_allocf(GoUintptr fp, GoUintptr ptr, GoUint64 osize, GoUint64 nsize);
#ifdef __cplusplus
}
#endif

@ -1 +0,0 @@
Subproject commit 4f917420d74aae84912acbaeb42e86691ddea309

View file

@ -1,6 +1,6 @@
package main
import lualib "github.com/CompeyDev/lei/internal"
import lualib "github.com/CompeyDev/lei/ffi"
func main() {
lua := lualib.LNewState()