Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
const std = @import("std");

const Build = std.Build;
pub const Language = lua_setup.Language;
const Step = std.Build.Step;
const Translator = @import("translate_c").Translator;

const lua_setup = @import("build/lua.zig");
const luau_setup = @import("build/luau.zig");
const luajit_setup = @import("build/luajit.zig");

/// The Lua version to compile and link.
pub const Language = enum {
lua51,
lua52,
lua53,
lua54,
lua55,
luajit,
luau,
};

pub const ApiCheck = enum {
/// Enables apicheck in debug builds.
debug,
/// Enables apicheck.
on,
/// Disables apicheck.
off,
};

pub fn build(b: *Build) void {
// Remove the default install and uninstall steps
b.top_level_steps = .{};
Expand All @@ -23,6 +42,7 @@ pub fn build(b: *Build) void {
const luau_use_4_vector = b.option(bool, "luau_use_4_vector", "Build Luau to use 4-vectors instead of the default 3-vector.") orelse false;
const lua_user_h = b.option(Build.LazyPath, "lua_user_h", "Lazy path to user supplied c header file") orelse null;
const additional_system_headers = b.option(Build.LazyPath, "additional_system_headers", "Lazy path to additional system headers to include when building Lua") orelse null;
const api_check = b.option(ApiCheck, "apicheck", "Enable parameter checks in the Lua API") orelse .debug;

if (lang == .luau and shared) {
std.debug.panic("Luau does not support compiling or loading shared modules", .{});
Expand Down Expand Up @@ -86,13 +106,14 @@ pub fn build(b: *Build) void {
}
} else if (b.lazyDependency(@tagName(lang), .{})) |upstream| {
const lib = switch (lang) {
.luajit => luajit_setup.configure(b, target, optimize, upstream, shared),
.luajit => luajit_setup.configure(b, target, optimize, upstream, shared, api_check),
.luau => luau_setup.configure(b, target, optimize, upstream, luau_use_4_vector),
else => lua_setup.configure(b, target, optimize, upstream, .{
.lang = lang,
.shared = shared,
.library_name = library_name,
.lua_user_h = lua_user_h,
.api_check = api_check,
}),
};

Expand Down
48 changes: 48 additions & 0 deletions build/header_gen.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! Concatenates two files together.

pub fn main(init: std.process.Init) !void {
const arena = init.arena.allocator();

var iter = try init.minimal.args.iterateAllocator(arena);

// Skip executable name
_ = iter.next();

const file1 = iter.next() orelse @panic("Missing file1 argument");
const file2 = iter.next() orelse @panic("Missing file2 argument");
const output_path = iter.next() orelse @panic("Missing output_path argument");
if (iter.next() != null) @panic("Too many arguments");

const output_file = try Io.Dir.cwd().openFile(init.io, output_file, .{});
defer output_file.close(init.io);
var out_buf: [4096]u8 = undefined;
var writer = output_file.writer(init.io, &out_buf);
defer (&writer.interface).flush() catch {};

{
const file = try Io.Dir.cwd().openFile(init.io, file1, .{ .mode = .read_only });
defer file.deinit(init.io);

var buf: [4096]u8 = undefined;
var reader = file.reader(init.io, &buf);

try (&reader.interface).stream(&writer.interface, .unlimited);
}

try (&writer.interface).writeByte('\n');

{
const file = try Io.Dir.cwd().openFile(init.io, file2, .{ .mode = .read_only });
defer file.deinit(init.io);

var buf: [4096]u8 = undefined;
var reader = file.reader(init.io, &buf);

try (&reader.interface).stream(&writer.interface, .unlimited);
}
}

const std = @import("std");
const Allocator = std.mem.Allocator;
const Io = std.Io;
const File = Io.File;
41 changes: 26 additions & 15 deletions build/lua.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ const std = @import("std");
const Build = std.Build;
const Step = std.Build.Step;

const applyPatchToFile = @import("utils.zig").applyPatchToFile;

pub const Language = enum {
lua51,
lua52,
lua53,
lua54,
lua55,
luajit,
luau,
};
const utils = @import("utils.zig");
const applyPatchToFile = utils.applyPatchToFile;
const concatenateFiles = utils.concatenateFiles;

const build = @import("../build.zig");

const ApiCheck = build.ApiCheck;
const Language = build.Language;

pub const Options = struct {
lang: Language,
shared: bool,
library_name: []const u8,
lua_user_h: ?Build.LazyPath,
api_check: ApiCheck,
};

pub fn configure(
Expand Down Expand Up @@ -60,6 +58,8 @@ pub fn configure(

const user_header = "user.h";

const enable_apicheck = opts.api_check == .on or (opts.api_check == .debug and optimize == .Debug);

const flags = [_][]const u8{
// Standard version used in Lua Makefile
"-std=gnu99",
Expand All @@ -73,12 +73,12 @@ pub fn configure(
},

// Enable api check
if (optimize == .Debug) "-DLUA_USE_APICHECK" else "",
if (lang == .lua55 and enable_apicheck) "-DLUA_USE_APICHECK" else "",

// Build as DLL for windows if shared
if (target.result.os.tag == .windows and shared) "-DLUA_BUILD_AS_DLL" else "",

if (lua_user_h) |_| b.fmt("-DLUA_USER_H=\"{s}\"", .{user_header}) else "",
if (enable_apicheck or lua_user_h != null) b.fmt("-DLUA_USER_H=\"{s}\"", .{user_header}) else "",
};

const lua_source_files = switch (lang) {
Expand Down Expand Up @@ -114,8 +114,19 @@ pub fn configure(
library.installHeader(upstream.path("src/luaconf.h"), "luaconf.h");

if (lua_user_h) |user_h| {
library.root_module.addIncludePath(user_h.dirname());
library.installHeader(user_h, user_header);
if (enable_apicheck) {
const concat = concatenateFiles(b, b.graph.host, user_h, b.path("src/user.h"), user_header);
library.step.dependOn(&concat.run.step);

library.root_module.addIncludePath(concat.output.dirname());
library.installHeader(concat.output, user_header);
} else {
library.root_module.addIncludePath(user_h.dirname());
library.installHeader(user_h, user_header);
}
} else if (enable_apicheck) {
library.root_module.addIncludePath(b.path("src"));
library.installHeader(b.path("src/user.h"), user_header);
}

return library;
Expand Down
17 changes: 16 additions & 1 deletion build/luajit.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@ const std = @import("std");
const Build = std.Build;
const Step = std.Build.Step;

const ApiCheck = @import("../build.zig").ApiCheck;

const applyPatchToFile = @import("utils.zig").applyPatchToFile;

pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, upstream: *Build.Dependency, shared: bool) *Step.Compile {
pub fn configure(
b: *Build,
target: Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
upstream: *Build.Dependency,
shared: bool,
api_check: ApiCheck,
) *Step.Compile {
// TODO: extract this to the main build function because it is shared between all specialized build functions

const lib = b.createModule(.{
Expand Down Expand Up @@ -216,12 +225,18 @@ pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.
library.root_module.addIncludePath(recdef_header.dirname());
library.root_module.addIncludePath(folddef_header.dirname());

const flags = [_][]const u8{
// Enable api check
if (api_check == .on or (api_check == .debug and optimize == .Debug)) "-DLUA_USE_APICHECK" else "",
};

lib.addCSourceFiles(.{
.root = .{ .dependency = .{
.dependency = upstream,
.sub_path = "",
} },
.files = &luajit_vm,
.flags = &flags,
});

lib.sanitize_c = .off;
Expand Down
31 changes: 29 additions & 2 deletions build/utils.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const std = @import("std");
const Build = std.Build;
const Step = std.Build.Step;

const PatchFile = struct {
const RunOutput = struct {
run: *Step.Run,
output: Build.LazyPath,
};
Expand All @@ -14,7 +14,7 @@ pub fn applyPatchToFile(
file: Build.LazyPath,
patch_file: Build.LazyPath,
output_file: []const u8,
) PatchFile {
) RunOutput {
const patch = b.addExecutable(.{
.name = "patch",
.root_module = b.createModule(.{
Expand All @@ -34,3 +34,30 @@ pub fn applyPatchToFile(
.output = out,
};
}

pub fn concatenateFiles(
b: *Build,
target: Build.ResolvedTarget,
file1: Build.LazyPath,
file2: Build.LazyPath,
output_file: []const u8,
) RunOutput {
const concatenate = b.addExecutable(.{
.name = "concat",
.root_module = b.createModule(.{
.root_source_file = b.path("build/header_gen.zig"),
.target = target,
}),
});

const concatenate_run = b.addRunArtifact(concatenate);
concatenate_run.addFileArg(file1);
concatenate_run.addFileArg(file2);

const out = concatenate_run.addOutputFileArg(output_file);

return .{
.run = concatenate_run,
.output = out,
};
}
11 changes: 9 additions & 2 deletions src/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ extern "c" fn zig_registerAssertionHandler() void;
/// This function is defined in luau.cpp and ensures Zig uses the correct free when compiling luau code
extern "c" fn zig_luau_free(ptr: *anyopaque) void;

export fn zlua_assert(ok: bool) void {
std.debug.assert(ok);
}

const Allocator = std.mem.Allocator;

// Types
Expand Down Expand Up @@ -4493,7 +4497,10 @@ pub const Lua = opaque {
pub fn openBit32(lua: *Lua) void {
switch (lang) {
.lua52, .lua53 => lua.requireF(c.LUA_BITLIBNAME, c.luaopen_bit32, true),
.luajit => lua.requireF(c.LUA_BITLIBNAME, c.luaopen_bit, true),
.luajit => {
lua.pushFunction(c.luaopen_bit);
lua.call(.{ .results = 1 });
},
else => @compileError(@src().fn_name ++ " is only available in Lua 5.2 and LuaJIT."),
}
lua.pop(1);
Expand Down Expand Up @@ -5451,7 +5458,7 @@ pub fn wrap(comptime function: anytype) TypeOfWrap(function) {
const lua: *Lua = @ptrCast(state.?);
if (str) |s| {
const buf = s[0..len];
return @call(.always_inline, function, .{lua, buf});
return @call(.always_inline, function, .{ lua, buf });
}
return -1;
}
Expand Down
4 changes: 4 additions & 0 deletions src/user.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extern void zlua_assert(int e);

#define luai_apicheck(l,e) zlua_assert(e)

Loading