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
This commit is contained in:
Erica Marigold 2025-04-26 08:50:50 +01:00
parent d82a23b44c
commit fb8d0c1514
Signed by: DevComp
SSH key fingerprint: SHA256:jD3oMT4WL3WHPJQbrjC3l5feNCnkv7ndW8nYaHX5wFw
2 changed files with 49 additions and 13 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/

View file

@ -19,25 +19,29 @@ 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 buildDirErr != nil && !os.IsExist(buildDirErr) {
bail(buildDirErr)
}
defaultCmakeFlags := []string{"..", "-DCMAKE_BUILD_TYPE=RelWithDebInfo", "-DLUAU_EXTERN_C=ON", "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"}
Exec("cmake", buildDir, append(defaultCmakeFlags, cmakeFlags...)...)
@ -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,11 +92,13 @@ 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)
}
@ -84,11 +110,17 @@ func main() {
}
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))
}
@ -110,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()