Files
neonucleus/build.zig
2026-06-02 09:11:02 -03:00

223 lines
7.2 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const LibBuildOpts = struct {
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
baremetal: bool,
bit32: bool,
};
fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
const strict = opts.optimize == .Debug;
const dataMod = b.createModule(.{
.target = opts.target,
.optimize = opts.optimize,
.strip = if (opts.optimize == .Debug) false else true,
.unwind_tables = if (opts.optimize == .Debug) null else .none,
.pic = true,
.sanitize_c = if (strict) .full else null,
});
dataMod.addCSourceFiles(.{
.files = &[_][]const u8{
"src/neonucleus.c",
"src/ncomplib.c",
},
.flags = &.{
if (opts.baremetal) "-DNN_BAREMETAL" else "",
if (opts.bit32) "-DNN_BIT32" else "",
if (strict) "-Wall" else "",
if (strict) "-Werror" else "",
"-std=gnu23",
"-Wno-keyword-macro", // cuz bools
"-fPIE",
},
});
if (!opts.baremetal) {
dataMod.link_libc = true; // we need a libc
}
dataMod.addIncludePath(b.path("src"));
return dataMod;
}
const LuaVersion = enum {
lua52,
lua53,
lua54,
};
fn compileRaylib(b: *std.Build, os: std.Target.Os.Tag, buildOpts: LibBuildOpts, c: *std.Build.Step.Compile) void {
// TODO: find out how to send our target to this build cmd
const targetStr = buildOpts.target.result.zigTriple(b.allocator) catch unreachable;
defer b.allocator.free(targetStr);
const targetArg = std.fmt.allocPrint(b.allocator, "-Dtarget={s}", .{targetStr}) catch unreachable;
defer b.allocator.free(targetArg);
// passing it breaks it for some reason?
// TODO: make it not break
const raylib = b.addSystemCommand(&.{ "zig", "build" });
raylib.setCwd(b.path("foreign/raylib/"));
raylib.stdio = .inherit;
c.step.dependOn(&raylib.step);
c.addIncludePath(b.path("foreign/raylib/zig-out/include/"));
c.addLibraryPath(b.path("foreign/raylib/zig-out/lib/"));
c.linkSystemLibrary("raylib");
if (os == .windows) {
c.linkSystemLibrary("WinMM");
c.linkSystemLibrary("GDI32"); // <---
c.linkSystemLibrary("User32"); // ^ Windows can't just rely on GDI
c.linkSystemLibrary("Shell32");
c.linkSystemLibrary("OpenGL32");
}
}
// For the test architecture, we specify the target Lua version we so desire.
// This can be checked for with Lua's _VERSION
fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version: LuaVersion) !*std.Build.Step.Compile {
const alloc = b.allocator;
const dirName = @tagName(version);
// its a static library because COFF is a pile of shit
const c = b.addLibrary(.{
.name = "lua",
.root_module = b.addModule("luamod", .{ .link_libc = true, .optimize = .ReleaseFast, .target = target, .pic = true }),
.linkage = .static,
});
const rootPath = try std.mem.join(alloc, std.fs.path.sep_str, &.{ "foreign", dirName });
// get all the .c files
var files = try std.ArrayList([]const u8).initCapacity(b.allocator, 0);
errdefer files.deinit(b.allocator);
var dir = try std.fs.cwd().openDir(rootPath, std.fs.Dir.OpenOptions{ .iterate = true });
defer dir.close();
var iter = dir.iterate();
while (try iter.next()) |e| {
if (std.mem.startsWith(u8, e.name, "l") and std.mem.endsWith(u8, e.name, ".c") and !std.mem.eql(u8, e.name, "lua.c")) {
const name = try alloc.dupe(u8, e.name);
try files.append(b.allocator, name);
}
}
c.addCSourceFiles(.{
.root = b.path(rootPath),
.files = files.items,
});
return c;
}
fn includeTheRightLua(b: *std.Build, c: *std.Build.Step.Compile, version: LuaVersion) !void {
const alloc = b.allocator;
const dirName = @tagName(version);
const rootPath = try std.mem.join(alloc, std.fs.path.sep_str, &.{ "foreign", dirName });
c.addIncludePath(b.path(rootPath));
}
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const os = target.result.os.tag;
const optimize = b.standardOptimizeOption(.{});
const opts = LibBuildOpts{
.target = target,
.optimize = optimize,
.baremetal = b.option(bool, "baremetal", "Compiles without libc integration") orelse false,
.bit32 = target.result.ptrBitWidth() == 32,
};
const noEmu = b.option(bool, "noEmu", "Disable compiling the emulator (fixes some build system quirks)") orelse false;
const includeFiles = b.addInstallHeaderFile(b.path("src/neonucleus.h"), "neonucleus.h");
const engineMod = addEngineSources(b, opts);
const engineStatic = b.addLibrary(.{
.name = "neonucleus",
.root_module = engineMod,
.linkage = .static,
});
const engineShared = b.addLibrary(.{
.name = if (os == .windows) "neonucleusdll" else "neonucleus",
.root_module = engineMod,
.linkage = .dynamic,
});
const engineStep = b.step("engine", "Builds the engine as a static library");
engineStep.dependOn(&engineStatic.step);
engineStep.dependOn(&includeFiles.step);
engineStep.dependOn(&b.addInstallArtifact(engineStatic, .{}).step);
const sharedStep = b.step("shared", "Builds the engine as a shared library");
sharedStep.dependOn(&engineShared.step);
sharedStep.dependOn(&includeFiles.step);
sharedStep.dependOn(&b.addInstallArtifact(engineShared, .{}).step);
if (!noEmu) {
const emulator = b.addExecutable(.{
.name = "neonucleus",
.root_module = b.addModule("emulator", .{
.target = target,
.optimize = optimize,
}),
});
emulator.linkLibC();
const sysraylib_flag = b.option(bool, "sysraylib", "Use the system raylib instead of compiling raylib") orelse false;
if (sysraylib_flag) {
emulator.linkSystemLibrary("raylib");
} else {
compileRaylib(b, os, opts, emulator);
}
const luaVer = b.option(LuaVersion, "lua", "The version of Lua to use.") orelse LuaVersion.lua53;
emulator.addCSourceFiles(.{
.files = &.{
"src/luaarch.c",
"src/main.c",
"src/glyphcache.c",
},
.flags = &.{
if (opts.baremetal) "-DNN_BAREMETAL" else "",
if (opts.bit32) "-DNN_BIT32" else "",
},
});
const l = try compileTheRightLua(b, target, luaVer);
try includeTheRightLua(b, emulator, luaVer);
// forces us to link in everything too
emulator.linkLibrary(l);
emulator.linkLibrary(engineStatic);
const emulatorStep = b.step("emulator", "Builds the emulator");
emulatorStep.dependOn(&emulator.step);
emulatorStep.dependOn(&b.addInstallArtifact(emulator, .{}).step);
var run_cmd = b.addRunArtifact(emulator);
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the emulator");
run_step.dependOn(emulatorStep);
run_step.dependOn(&run_cmd.step);
}
}