Skip to content
Merged
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
14 changes: 12 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ pub const ApiCheck = enum {
off,
};

pub const ApiCheckType = enum {
/// Apicheck with Zig stack traces for supported Lua verions.
stack_trace,
/// Default Lua api checks.
basic,
};

pub fn build(b: *Build) void {
// Remove the default install and uninstall steps
b.top_level_steps = .{};
Expand All @@ -42,7 +49,9 @@ 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", "Slice of Lazy paths 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;
const api_check = b.option(ApiCheck, "apicheck", "Enable parameter check assertions in the Lua API") orelse .debug;
// TODO: if the stack traces go well and don't error, maybe remove this. Why would someone not want the stack trace?
const api_check_type = b.option(ApiCheckType, "apicheck_type", "Whether apicheck should show stack traces or only abort") orelse .stack_trace;

if (lang == .luau and shared) {
std.debug.panic("Luau does not support compiling or loading shared modules", .{});
Expand Down Expand Up @@ -108,14 +117,15 @@ pub fn build(b: *Build) void {
t.mod.linkSystemLibrary(system_library_name, .{ .preferred_link_mode = link_mode });
} 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,
.api_check_type = api_check_type,
}),
};

Expand Down
6 changes: 6 additions & 0 deletions build/include/assert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This will be included when <assert.h> is included when LUA_USE_APICHECK is
// defined. Undefines any assert that may have already been defined, and then
// defines assert to be the zlua_assert function that shows a stack trace.
#undef assert
extern void zlua_assert(int e);
#define assert(e) zlua_assert((e) ? 1 : 0)
14 changes: 11 additions & 3 deletions build/lua.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ const std = @import("std");
const Build = std.Build;
const Step = std.Build.Step;

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

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

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

pub const Options = struct {
Expand All @@ -16,6 +18,7 @@ pub const Options = struct {
library_name: []const u8,
lua_user_h: ?Build.LazyPath,
api_check: ApiCheck,
api_check_type: ApiCheckType,
};

pub fn configure(
Expand Down Expand Up @@ -56,6 +59,8 @@ pub fn configure(

const user_header = "user.h";

const apicheck_enabled = 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 @@ -69,12 +74,12 @@ pub fn configure(
},

// Enable api check
if (opts.api_check == .on or (opts.api_check == .debug and optimize == .debug)) "-DLUA_USE_APICHECK" else "",
if (apicheck_enabled) "-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 (lua_user_h != null) b.fmt("-DLUA_USER_H=\"{s}\"", .{user_header}) else "",
if (target.result.cpu.arch == .wasm32) "-flto" else "",
};

Expand Down Expand Up @@ -110,6 +115,9 @@ pub fn configure(
library.installHeader(upstream.path("src/lauxlib.h"), "lauxlib.h");
library.installHeader(upstream.path("src/luaconf.h"), "luaconf.h");

// This adds build/include/assert.h to the include path so Lua finds it before the system <assert.h>.
if (apicheck_enabled and opts.api_check_type == .stack_trace) library.root_module.addIncludePath(b.path("build/include"));

if (lua_user_h) |user_h| {
library.root_module.addIncludePath(user_h.dirname());
library.installHeader(user_h, user_header);
Expand Down
18 changes: 17 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 @@ -227,12 +236,19 @@ 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
// TODO: can we support zig stack traces for LuaJIT too?
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
12 changes: 7 additions & 5 deletions src/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ 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;

/// Called from C for Lua function parameter check assertions when LUA_USE_APICHECK is defined.
/// Essentially, this is used in place of C's assert so stack traces are shown.
export fn zlua_assert(ok: bool) void {
std.debug.assert(ok);
}

const Allocator = std.mem.Allocator;

// Types
Expand Down Expand Up @@ -731,12 +737,8 @@ pub const Lua = opaque {
} else if (nsize == 0) {
return null;
} else {
const builtin = @import("builtin"); // FIXME: remove when zig-0.15 is released and 0.14 can be dropped
// ptr is null, allocate a new block of memory
const new_ptr = (if (builtin.zig_version.major == 0 and builtin.zig_version.minor < 15)
allocator_ptr.alignedAlloc(u8, alignment, nsize)
else
allocator_ptr.alignedAlloc(u8, .fromByteUnits(alignment), nsize)) catch return null;
const new_ptr = allocator_ptr.alignedAlloc(u8, .fromByteUnits(alignment), nsize) catch return null;
return new_ptr.ptr;
}
}
Expand Down
Loading