Skip to content

Commit da7499c

Browse files
authored
Merge pull request #159 from hubidubi13/main
Add build option to provide an additional header file to the Lua compilation
2 parents b1fa628 + 88bce80 commit da7499c

File tree

5 files changed

+105
-2
lines changed

5 files changed

+105
-2
lines changed

build.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,16 @@ pub fn build(b: *Build) void {
1919
const library_name = b.option([]const u8, "library_name", "Library name for lua linking, default is `lua`") orelse "lua";
2020
const shared = b.option(bool, "shared", "Build shared library instead of static") orelse false;
2121
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;
22+
const lua_user_h = b.option(Build.LazyPath, "lua_user_h", "Lazy path to user supplied c header file") orelse null;
2223

2324
if (lang == .luau and shared) {
2425
std.debug.panic("Luau does not support compiling or loading shared modules", .{});
2526
}
2627

28+
if (lua_user_h != null and (lang == .luajit or lang == .luau)) {
29+
std.debug.panic("Only basic lua supports a user provided header file", .{});
30+
}
31+
2732
// Zig module
2833
const zlua = b.addModule("zlua", .{
2934
.root_source_file = b.path("src/lib.zig"),
@@ -44,7 +49,7 @@ pub fn build(b: *Build) void {
4449
const lib = switch (lang) {
4550
.luajit => luajit_setup.configure(b, target, optimize, upstream, shared),
4651
.luau => luau_setup.configure(b, target, optimize, upstream, luau_use_4_vector),
47-
else => lua_setup.configure(b, target, optimize, upstream, lang, shared, library_name),
52+
else => lua_setup.configure(b, target, optimize, upstream, lang, shared, library_name, lua_user_h),
4853
};
4954

5055
// Expose the Lua artifact, and get an install step that header translation can refer to
@@ -103,6 +108,7 @@ pub fn build(b: *Build) void {
103108
var common_examples = [_]struct { []const u8, []const u8 }{
104109
.{ "interpreter", "examples/interpreter.zig" },
105110
.{ "zig-function", "examples/zig-fn.zig" },
111+
.{ "multithreaded", "examples/multithreaded.zig" },
106112
};
107113
const luau_examples = [_]struct { []const u8, []const u8 }{
108114
.{ "luau-bytecode", "examples/luau-bytecode.zig" },

build/lua.zig

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub const Language = enum {
1212
luau,
1313
};
1414

15-
pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, upstream: *Build.Dependency, lang: Language, shared: bool, library_name: []const u8) *Step.Compile {
15+
pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, upstream: *Build.Dependency, lang: Language, shared: bool, library_name: []const u8, lua_user_h: ?Build.LazyPath) *Step.Compile {
1616
const version: std.SemanticVersion = switch (lang) {
1717
.lua51 => .{ .major = 5, .minor = 1, .patch = 5 },
1818
.lua52 => .{ .major = 5, .minor = 2, .patch = 4 },
@@ -38,6 +38,8 @@ pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.
3838

3939
lib.addIncludePath(upstream.path("src"));
4040

41+
const user_header = "user.h";
42+
4143
const flags = [_][]const u8{
4244
// Standard version used in Lua Makefile
4345
"-std=gnu99",
@@ -55,6 +57,8 @@ pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.
5557

5658
// Build as DLL for windows if shared
5759
if (target.result.os.tag == .windows and shared) "-DLUA_BUILD_AS_DLL" else "",
60+
61+
if (lua_user_h) |_| b.fmt("-DLUA_USER_H=\"{s}\"", .{user_header}) else "",
5862
};
5963

6064
const lua_source_files = switch (lang) {
@@ -87,6 +91,11 @@ pub fn configure(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.
8791
lib.installHeader(upstream.path("src/lauxlib.h"), "lauxlib.h");
8892
lib.installHeader(upstream.path("src/luaconf.h"), "luaconf.h");
8993

94+
if (lua_user_h) |user_h| {
95+
lib.addIncludePath(user_h.dirname());
96+
lib.installHeader(user_h, user_header);
97+
}
98+
9099
return lib;
91100
}
92101

examples/multithreaded.zig

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//! Multi threaded lua program
2+
//! The additional header must be passed to the build using `-Dlua_user_h=examples/user.h`
3+
//! Checkout http://lua-users.org/wiki/ThreadsTutorial for more info
4+
5+
const std = @import("std");
6+
const zlua = @import("zlua");
7+
8+
var mutex = std.Thread.Mutex{};
9+
10+
export fn lua_zlock(L: *zlua.LuaState) callconv(.C) void {
11+
_ = L;
12+
mutex.lock();
13+
}
14+
15+
export fn lua_zunlock(L: *zlua.LuaState) callconv(.C) void {
16+
_ = L;
17+
mutex.unlock();
18+
}
19+
20+
fn add_to_x(lua: *zlua.Lua, num: usize) void {
21+
for (0..num) |_| {
22+
// omit error handling for brevity
23+
lua.loadString("x = x + 1\n") catch return;
24+
lua.protectedCall(.{}) catch return;
25+
}
26+
27+
const size = 256;
28+
var buf = [_:0]u8{0} ** size;
29+
_ = std.fmt.bufPrint(&buf, "print(\"{}: \", x)", .{std.Thread.getCurrentId()}) catch return;
30+
31+
// The printing from different threads does not always work nicely
32+
// There seems to be a separate sterr lock on each argument to print
33+
lua.loadString(&buf) catch return;
34+
lua.protectedCall(.{}) catch return;
35+
}
36+
37+
pub fn main() anyerror!void {
38+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
39+
const allocator = gpa.allocator();
40+
defer _ = gpa.deinit();
41+
42+
// Initialize The Lua vm and get a reference to the main thread
43+
var lua = try zlua.Lua.init(allocator);
44+
defer lua.deinit();
45+
46+
lua.openLibs();
47+
48+
// create a global variable accessible by all threads
49+
// omit error handling for brevity
50+
try lua.loadString("_G.x = 0\n");
51+
try lua.protectedCall(.{});
52+
53+
const num = 1_000;
54+
const n_jobs = 5;
55+
var subs: [n_jobs]*zlua.Lua = undefined;
56+
57+
// create a thread pool to run all the functions
58+
var pool: std.Thread.Pool = undefined;
59+
try pool.init(.{ .allocator = allocator, .n_jobs = n_jobs });
60+
defer pool.deinit();
61+
62+
var wg: std.Thread.WaitGroup = .{};
63+
64+
for (0..n_jobs) |i| {
65+
subs[i] = lua.newThread();
66+
pool.spawnWg(&wg, add_to_x, .{ subs[i], num });
67+
}
68+
69+
// also do the thing from the main thread
70+
add_to_x(lua, num);
71+
72+
wg.wait();
73+
74+
for (subs) |sub| {
75+
try lua.closeThread(sub);
76+
}
77+
78+
// print the final value
79+
try lua.loadString("print(x)\n");
80+
try lua.protectedCall(.{});
81+
}

examples/user.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#define lua_lock(L) lua_zlock(L)
2+
#define lua_unlock(L) lua_zunlock(L)
3+
4+
void lua_zlock(lua_State* L);
5+
void lua_zunlock(lua_State* L);
6+

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ There are currently three additional options that can be passed to `b.dependency
6666
* `.lang`: Set the Lua language to build and embed. Defaults to `.lua54`. Possible values are `.lua51`, `.lua52`, `.lua53`, `.lua54`, and `luau`.
6767
* `.shared`: Defaults to `false` for embedding in a Zig program. Set to `true` to dynamically link the Lua source code (useful for creating shared modules).
6868
* `luau_use_4_vector`: defaults to false. Set to true to use 4-vectors instead of the default 3-vector in Luau.
69+
* `lua_user_h`: defaults to null. Provide a path to an additional header file for the Lua compilation. Must be set to to `examples/user.h` in order to run the multithreaded example.
6970

7071
For example, here is a `b.dependency()` call that and links against a shared Lua 5.2 library:
7172

0 commit comments

Comments
 (0)