For my own edutainment, I was interested in using zig to write some mods for quake 2, using the yamagi quake 2 fork. I had the general idea of just getting zig to compile the c code (into a game.dll that the engine then loads) and then incrementally adjusting the output to use zig functions instead. first wrappers, then more complex behaviors.
My knowledge of dlls, linking, and building in general is limited, and I’m not sure if this is even something that can be done inside of a build.zig file.
the include/ directory contains some files pulled directly from the yquake2 source.
I’m sufficiently out of my depth that this could be completely off-base and not even the right question to be asking, so I welcome any such corrections!
here is the contents of my build.zig file, currently outputting a bunch of (expected?) linker errors:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// NOTE: https://ziggit.dev/t/link-against-static-c-library-with-zig-0-16/15234/7
// this was originally for the game.h file when i just wanted types/declarations
// I first tried changing it to the g_main.c to see if that would work but it does not.
const q2_game = b.addTranslateC(.{
.root_source_file = b.path("include/game/g_main.c"),
.optimize = optimize,
.target = target,
});
const q2_mod = q2_game.createModule();
const mod = b.addModule("sportsball", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "q2", .module = q2_mod },
},
});
mod.addCSourceFiles(.{
.files = &.{
"include/game/g_main.c",
"include/game/g_ai.c",
"include/game/g_chase.c",
"include/game/g_cmds.c",
"include/game/g_combat.c",
"include/game/g_func.c",
"include/game/g_items.c",
"include/game/g_misc.c",
"include/game/g_monster.c",
"include/game/g_phys.c",
"include/game/g_spawn.c",
"include/game/g_svcmds.c",
"include/game/g_target.c",
"include/game/g_trigger.c",
"include/game/g_turret.c",
"include/game/g_utils.c",
"include/game/g_weapon.c",
// player/ and monster/ files too
},
.flags = &.{"-std=c99 -shared"},
});
mod.addIncludePath(b.path("include/common"));
mod.addIncludePath(b.path("include/game"));
mod.addIncludePath(b.path("include"));
const game_dll = b.addLibrary(.{
.linkage = .dynamic,
.name = "game",
.root_module = mod,
});
const q2_path = b.option(
[]const u8,
"q2_path",
"destination directory for the game.dll",
);
if (q2_path) |q2| {
b.install_path = q2;
std.log.info("q2 path: {s}", .{q2});
std.log.info("b.install_path: {s}", .{b.install_path});
}
const copy_step = b.step("copy-mod", "Copy game.dll to q2_path");
const q2_mod_dir: std.Build.InstallDir = .{
.custom = "baseq2",
};
const dll_artifact = b.addInstallArtifact(game_dll, .{
.dest_dir = .{
.override = q2_mod_dir,
},
});
copy_step.dependOn(&dll_artifact.step);
}