Skip to content

Commit db29119

Browse files
committed
Add initial LuaJIT support
Adds the latest release of LuaJIT v2.1 and all necessary build file changes to build as a static library. This has only been tested on aarch64 macos. Many LuaJIT flags are missing from the build config. Even if it works, it may not be working perfectly. Uses the Lua 51 library bindings, so some additional LuaJIT functions may be missing. These will be audited and added at a later time. Part of #19
1 parent f03efd2 commit db29119

File tree

4 files changed

+298
-27
lines changed

4 files changed

+298
-27
lines changed

build.zig

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub const Language = enum {
88
lua52,
99
lua53,
1010
lua54,
11+
luajit,
1112
luau,
1213
};
1314

@@ -34,6 +35,7 @@ pub fn build(b: *Build) void {
3435
.lua52 => .{ .path = "src/lib52.zig" },
3536
.lua53 => .{ .path = "src/lib53.zig" },
3637
.lua54 => .{ .path = "src/lib54.zig" },
38+
.luajit => .{ .path = "src/lib51.zig" },
3739
.luau => .{ .path = "src/libluau.zig" },
3840
},
3941
});
@@ -50,6 +52,7 @@ pub fn build(b: *Build) void {
5052
}
5153

5254
const lib = switch (lang) {
55+
.luajit => buildLuaJIT(b, target, optimize, upstream, shared),
5356
.luau => buildLuau(b, target, optimize, upstream, luau_use_4_vector),
5457
else => buildLua(b, target, optimize, upstream, lang, shared),
5558
};
@@ -118,6 +121,7 @@ pub fn build(b: *Build) void {
118121
.lua52 => .{ .path = "src/lib52.zig" },
119122
.lua53 => .{ .path = "src/lib53.zig" },
120123
.lua54 => .{ .path = "src/lib54.zig" },
124+
.luajit => .{ .path = "src/lib51.zig" },
121125
.luau => .{ .path = "src/libluau.zig" },
122126
},
123127
});
@@ -131,6 +135,7 @@ pub fn build(b: *Build) void {
131135
.lua52 => "docs/lua52",
132136
.lua53 => "docs/lua53",
133137
.lua54 => "docs/lua54",
138+
.luajit => "docs/luajit",
134139
.luau => "docs/luau",
135140
},
136141
});
@@ -246,6 +251,187 @@ fn buildLuau(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.Opti
246251
return lib;
247252
}
248253

254+
fn buildLuaJIT(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, upstream: *Build.Dependency, shared: bool) *Step.Compile {
255+
// TODO: extract this to the main build function because it is shared between all specialized build functions
256+
const lib_opts = .{
257+
.name = "lua",
258+
.target = target,
259+
.optimize = optimize,
260+
};
261+
const lib: *Step.Compile = if (shared)
262+
b.addSharedLibrary(lib_opts)
263+
else
264+
b.addStaticLibrary(lib_opts);
265+
266+
// Compile minilua interpreter used at build time to generate files
267+
const minilua = b.addExecutable(.{
268+
.name = "minilua",
269+
.target = target, // TODO ensure this is the host
270+
.optimize = .ReleaseSafe,
271+
});
272+
minilua.linkLibC();
273+
minilua.root_module.sanitize_c = false;
274+
minilua.addCSourceFile(.{.file = upstream.path("src/host/minilua.c")});
275+
276+
// Generate the buildvm_arch.h file using minilua
277+
const dynasm_run = b.addRunArtifact(minilua);
278+
dynasm_run.addFileArg(upstream.path("dynasm/dynasm.lua"));
279+
280+
// TODO: Many more flags to figure out
281+
if (target.result.cpu.arch.endian() == .little) {
282+
dynasm_run.addArgs(&.{ "-D", "ENDIAN_LE" });
283+
} else {
284+
dynasm_run.addArgs(&.{ "-D", "ENDIAN_BE" });
285+
}
286+
287+
if (target.result.ptrBitWidth() == 64) dynasm_run.addArgs(&.{ "-D", "P64" });
288+
dynasm_run.addArgs(&.{ "-D", "JIT", "-D", "FFI" });
289+
290+
if (target.result.abi.floatAbi() == .hard) {
291+
dynasm_run.addArgs(&.{ "-D", "FPU", "-D", "HFABI" });
292+
}
293+
294+
if (target.result.os.tag == .windows) dynasm_run.addArgs(&.{ "-D", "WIN" });
295+
296+
dynasm_run.addArg("-o");
297+
const buildvm_arch_h = dynasm_run.addOutputFileArg("buildvm_arch.h");
298+
299+
dynasm_run.addFileArg(upstream.path(switch(target.result.cpu.arch) {
300+
.x86 => "src/vm_x86.dasc",
301+
.x86_64 => "src/vm_x64.dasc",
302+
.arm, .armeb => "src/vm_arm.dasc",
303+
.aarch64, .aarch64_be => "src/vm_arm64.dasc",
304+
.powerpc, .powerpcle => "src/vm_ppc.dasc",
305+
.mips, .mipsel => "src/vm_mips.dasc",
306+
.mips64, .mips64el => "src/vm_mips64.dasc",
307+
else => @panic("Unsupported architecture"),
308+
}));
309+
310+
// Generate luajit.h using minilua
311+
const genversion_run = b.addRunArtifact(minilua);
312+
genversion_run.addFileArg(upstream.path("src/host/genversion.lua"));
313+
genversion_run.addFileArg(upstream.path("src/luajit_rolling.h"));
314+
genversion_run.addFileArg(upstream.path(".relver"));
315+
const luajit_h = genversion_run.addOutputFileArg("luajit.h");
316+
317+
// Compile the buildvm executable used to generate other files
318+
const buildvm = b.addExecutable(.{
319+
.name = "buildvm",
320+
.target = target, // TODO ensure this is the host
321+
.optimize = .ReleaseSafe,
322+
});
323+
buildvm.linkLibC();
324+
buildvm.root_module.sanitize_c = false;
325+
326+
// Needs to run after the buildvm_arch.h and luajit.h files are generated
327+
buildvm.step.dependOn(&dynasm_run.step);
328+
buildvm.step.dependOn(&genversion_run.step);
329+
330+
buildvm.addCSourceFiles(.{
331+
.dependency = upstream,
332+
.files = &.{ "src/host/buildvm_asm.c", "src/host/buildvm_fold.c", "src/host/buildvm_lib.c", "src/host/buildvm_peobj.c", "src/host/buildvm.c" },
333+
});
334+
335+
buildvm.addIncludePath(upstream.path("src"));
336+
buildvm.addIncludePath(upstream.path("src/host"));
337+
buildvm.addIncludePath(buildvm_arch_h.dirname());
338+
buildvm.addIncludePath(luajit_h.dirname());
339+
340+
// Use buildvm to generate files and headers used in the final vm
341+
const buildvm_bcdef = b.addRunArtifact(buildvm);
342+
buildvm_bcdef.addArgs(&.{ "-m", "bcdef", "-o" });
343+
const bcdef_header = buildvm_bcdef.addOutputFileArg("lj_bcdef.h");
344+
for (luajit_lib) |file| {
345+
buildvm_bcdef.addFileArg(upstream.path(file));
346+
}
347+
348+
const buildvm_ffdef = b.addRunArtifact(buildvm);
349+
buildvm_ffdef.addArgs(&.{ "-m", "ffdef", "-o" });
350+
const ffdef_header = buildvm_ffdef.addOutputFileArg("lj_ffdef.h");
351+
for (luajit_lib) |file| {
352+
buildvm_ffdef.addFileArg(upstream.path(file));
353+
}
354+
355+
const buildvm_libdef = b.addRunArtifact(buildvm);
356+
buildvm_libdef.addArgs(&.{ "-m", "libdef", "-o" });
357+
const libdef_header = buildvm_libdef.addOutputFileArg("lj_libdef.h");
358+
for (luajit_lib) |file| {
359+
buildvm_libdef.addFileArg(upstream.path(file));
360+
}
361+
362+
const buildvm_recdef = b.addRunArtifact(buildvm);
363+
buildvm_recdef.addArgs(&.{ "-m", "recdef", "-o" });
364+
const recdef_header = buildvm_recdef.addOutputFileArg("lj_recdef.h");
365+
for (luajit_lib) |file| {
366+
buildvm_recdef.addFileArg(upstream.path(file));
367+
}
368+
369+
const buildvm_folddef = b.addRunArtifact(buildvm);
370+
buildvm_folddef.addArgs(&.{ "-m", "folddef", "-o" });
371+
const folddef_header = buildvm_folddef.addOutputFileArg("lj_folddef.h");
372+
for (luajit_lib) |file| {
373+
buildvm_folddef.addFileArg(upstream.path(file));
374+
}
375+
376+
const buildvm_ljvm = b.addRunArtifact(buildvm);
377+
buildvm_ljvm.addArg("-m");
378+
379+
if (target.result.os.tag == .windows) {
380+
buildvm_ljvm.addArg("peobj");
381+
} else if (target.result.isDarwin()) {
382+
buildvm_ljvm.addArg("machasm");
383+
} else {
384+
buildvm_ljvm.addArg("elfasm");
385+
}
386+
387+
buildvm_ljvm.addArg("-o");
388+
if (target.result.os.tag == .windows) {
389+
const ljvm_ob = buildvm_ljvm.addOutputFileArg("lj_vm. o");
390+
lib.addObjectFile(ljvm_ob);
391+
} else {
392+
const ljvm_asm = buildvm_ljvm.addOutputFileArg("lj_vm.S");
393+
lib.addAssemblyFile(ljvm_asm);
394+
}
395+
396+
// Finally build LuaJIT after generating all the files
397+
lib.step.dependOn(&genversion_run.step);
398+
lib.step.dependOn(&buildvm_bcdef.step);
399+
lib.step.dependOn(&buildvm_ffdef.step);
400+
lib.step.dependOn(&buildvm_libdef.step);
401+
lib.step.dependOn(&buildvm_recdef.step);
402+
lib.step.dependOn(&buildvm_folddef.step);
403+
lib.step.dependOn(&buildvm_ljvm.step);
404+
405+
lib.linkLibC();
406+
407+
lib.defineCMacro("LUAJIT_UNWIND_EXTERNAL", null);
408+
lib.linkSystemLibrary("unwind");
409+
lib.root_module.unwind_tables = true;
410+
411+
lib.addIncludePath(upstream.path("src"));
412+
lib.addIncludePath(luajit_h.dirname());
413+
lib.addIncludePath(bcdef_header.dirname());
414+
lib.addIncludePath(ffdef_header.dirname());
415+
lib.addIncludePath(libdef_header.dirname());
416+
lib.addIncludePath(recdef_header.dirname());
417+
lib.addIncludePath(folddef_header.dirname());
418+
419+
lib.addCSourceFiles(.{
420+
.dependency = upstream,
421+
.files = &luajit_vm,
422+
});
423+
424+
lib.root_module.sanitize_c = false;
425+
426+
installHeader(lib, upstream.path("src/lua.h"), "lua.h");
427+
installHeader(lib, upstream.path("src/lualib.h"), "lualib.h");
428+
installHeader(lib, upstream.path("src/lauxlib.h"), "lauxlib.h");
429+
installHeader(lib, upstream.path("src/luaconf.h"), "luaconf.h");
430+
installHeader(lib, luajit_h, "luajit.h");
431+
432+
return lib;
433+
}
434+
249435
const lua_base_source_files = [_][]const u8{
250436
"src/lapi.c",
251437
"src/lcode.c",
@@ -297,6 +483,81 @@ const lua_54_source_files = lua_base_source_files ++ [_][]const u8{
297483
"src/lutf8lib.c",
298484
};
299485

486+
const luajit_lib = [_][]const u8 {
487+
"src/lib_base.c",
488+
"src/lib_math.c",
489+
"src/lib_bit.c",
490+
"src/lib_string.c",
491+
"src/lib_table.c",
492+
"src/lib_io.c",
493+
"src/lib_os.c",
494+
"src/lib_package.c",
495+
"src/lib_debug.c",
496+
"src/lib_jit.c",
497+
"src/lib_ffi.c",
498+
"src/lib_buffer.c",
499+
};
500+
501+
const luajit_vm = luajit_lib ++ [_][]const u8{
502+
"src/lj_assert.c",
503+
"src/lj_gc.c",
504+
"src/lj_err.c",
505+
"src/lj_char.c",
506+
"src/lj_bc.c",
507+
"src/lj_obj.c",
508+
"src/lj_buf.c",
509+
"src/lj_str.c",
510+
"src/lj_tab.c",
511+
"src/lj_func.c",
512+
"src/lj_udata.c",
513+
"src/lj_meta.c",
514+
"src/lj_debug.c",
515+
"src/lj_prng.c",
516+
"src/lj_state.c",
517+
"src/lj_dispatch.c",
518+
"src/lj_vmevent.c",
519+
"src/lj_vmmath.c",
520+
"src/lj_strscan.c",
521+
"src/lj_strfmt.c",
522+
"src/lj_strfmt_num.c",
523+
"src/lj_serialize.c",
524+
"src/lj_api.c",
525+
"src/lj_profile.c",
526+
"src/lj_lex.c",
527+
"src/lj_parse.c",
528+
"src/lj_bcread.c",
529+
"src/lj_bcwrite.c",
530+
"src/lj_load.c",
531+
"src/lj_ir.c",
532+
"src/lj_opt_mem.c",
533+
"src/lj_opt_fold.c",
534+
"src/lj_opt_narrow.c",
535+
"src/lj_opt_dce.c",
536+
"src/lj_opt_loop.c",
537+
"src/lj_opt_split.c",
538+
"src/lj_opt_sink.c",
539+
"src/lj_mcode.c",
540+
"src/lj_snap.c",
541+
"src/lj_record.c",
542+
"src/lj_crecord.c",
543+
"src/lj_ffrecord.c",
544+
"src/lj_asm.c",
545+
"src/lj_trace.c",
546+
"src/lj_gdbjit.c",
547+
"src/lj_ctype.c",
548+
"src/lj_cdata.c",
549+
"src/lj_cconv.c",
550+
"src/lj_ccall.c",
551+
"src/lj_ccallback.c",
552+
"src/lj_carith.c",
553+
"src/lj_clib.c",
554+
"src/lj_cparse.c",
555+
"src/lj_lib.c",
556+
"src/lj_alloc.c",
557+
"src/lib_aux.c",
558+
"src/lib_init.c",
559+
};
560+
300561
const luau_source_files = [_][]const u8{
301562
"Compiler/src/BuiltinFolding.cpp",
302563
"Compiler/src/Builtins.cpp",

build.zig.zon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
.hash = "1220f93ada1fa077ab096bf88a5b159ad421dbf6a478edec78ddb186d0c21d3476d9",
3030
},
3131

32+
.luajit = .{
33+
.url = "https://github.com/LuaJIT/LuaJIT/archive/c525bcb9024510cad9e170e12b6209aedb330f83.tar.gz",
34+
.hash = "1220ae2d84cfcc2a7aa670661491f21bbed102d335de18ce7d36866640fd9dfcc33a",
35+
},
36+
3237
.luau = .{
3338
.url = "https://github.com/luau-lang/luau/archive/refs/tags/0.607.tar.gz",
3439
.hash = "122003818ff2aa912db37d4bbda314ff9ff70d03d9243af4b639490be98e2bfa7cb6",

src/lib51.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const c = @cImport({
77
@cInclude("lua.h");
88
@cInclude("lualib.h");
99
@cInclude("lauxlib.h");
10+
11+
if (lang == .luajit) @cInclude("luajit.h");
1012
});
1113

1214
const config = @import("config");

0 commit comments

Comments
 (0)