srctree

blame
build.zig
const std = @import("std"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const ver = version(b); const options = b.addOptions(); options.addOption([]const u8, "version", ver); const verse_lib = b.addModule("verse", .{ .root_source_file = b.path("src/verse.zig"), .target = target, .optimize = optimize, }); verse_lib.addOptions("build_options", options); const lib_unit_tests = b.addTest(.{ .root_source_file = b.path("src/verse.zig"), .target = target, .optimize = optimize, }); lib_unit_tests.root_module.addOptions("build_options", options); var compiler = Compiler.init(b); var comptime_structs: ?*std.Build.Module = null; var comptime_templates: ?*std.Build.Module = null; if (std.fs.cwd().access("src/fallback_html/index.html", .{})) { compiler.addDir("src/fallback_html/"); compiler.addDir("examples/templates/"); compiler.collect() catch unreachable; comptime_templates = compiler.buildTemplates() catch unreachable; // Zig build time doesn't expose it's state in a way I know how to check... // so we yolo it like python :D lib_unit_tests.root_module.addImport("comptime_templates", comptime_templates orelse unreachable); comptime_structs = compiler.buildStructs() catch unreachable; lib_unit_tests.root_module.addImport("comptime_structs", comptime_structs orelse unreachable); verse_lib.addImport("comptime_structs", comptime_structs orelse @panic("structs missing")); verse_lib.addImport("comptime_templates", comptime_templates orelse @panic("structs missing")); } else |_| {} const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_lib_unit_tests.step); const examples = [_][]const u8{ "basic", "cookies", "template", "endpoint", "auth-cookie", "request-userdata", "api", "websocket", }; inline for (examples) |example| { const example_exe = b.addExecutable(.{ .name = example, .root_source_file = b.path("examples/" ++ example ++ ".zig"), .target = target, .optimize = optimize, }); // All Examples should compile for tests to pass test_step.dependOn(&example_exe.step); example_exe.root_module.addImport("verse", verse_lib); const run_example = b.addRunArtifact(example_exe); run_example.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_example.addArgs(args); } const run_name = "run-" ++ example; const run_description = "Run example: " ++ example; const run_step = b.step(run_name, run_description); run_step.dependOn(&run_example.step); } } pub const Compiler = struct { b: *std.Build, dirs: std.ArrayList([]const u8), files: std.ArrayList([]const u8), collected: std.ArrayList([]const u8), templates: ?*std.Build.Module = null, structs: ?*std.Build.Module = null, debugging: bool = false, pub fn init(b: *std.Build) Compiler { return .{ .b = b, .dirs = std.ArrayList([]const u8).init(b.allocator), .files = std.ArrayList([]const u8).init(b.allocator), .collected = std.ArrayList([]const u8).init(b.allocator), }; } pub fn raze(self: Compiler) void { for (self.dirs.items) |each| self.b.allocator.free(each); self.dirs.deinit(); for (self.files.items) |each| self.b.allocator.free(each); self.files.deinit(); for (self.collected.items) |each| self.b.allocator.free(each); self.collected.deinit(); } pub fn addDir(self: *Compiler, dir: []const u8) void { const copy = self.b.allocator.dupe(u8, dir) catch @panic("OOM"); self.dirs.append(copy) catch @panic("OOM"); self.templates = null; self.structs = null; } pub fn addFile(self: *Compiler, file: []const u8) void { const copy = self.b.allocator.dupe(u8, file) catch @panic("OOM"); self.files.append(copy) catch @panic("OOM"); self.templates = null; self.structs = null; } pub fn buildTemplates(self: *Compiler) !*std.Build.Module { if (self.templates) |t| return t; //std.debug.print("building for {}\n", .{self.collected.items.len}); const local_dir = std.fs.path.dirname(@src().file) orelse "."; const compiled = self.b.createModule(.{ .root_source_file = .{ .cwd_relative = self.b.pathJoin(&.{ local_dir, "src/template/comptime.zig" }), }, }); const found = self.b.addOptions(); found.addOption([]const []const u8, "names", self.collected.items); compiled.addOptions("config", found); for (self.collected.items) |file| { _ = compiled.addAnonymousImport(file, .{ .root_source_file = self.b.path(file), }); } self.templates = compiled; return compiled; } pub fn buildStructs(self: *Compiler) !*std.Build.Module { if (self.structs) |s| return s; if (self.debugging) std.debug.print("building structs for {}\n", .{self.collected.items.len}); const local_dir = std.fs.path.dirname(@src().file) orelse "."; const t_compiler = self.b.addExecutable(.{ .name = "template-compiler", .root_source_file = .{ .cwd_relative = self.b.pathJoin(&.{ local_dir, "src/template/struct-emit.zig" }), }, .target = self.b.graph.host, }); const comptime_templates = try self.buildTemplates(); t_compiler.root_module.addImport("comptime_templates", comptime_templates); const tc_build_run = self.b.addRunArtifact(t_compiler); const tc_structs = tc_build_run.addOutputFileArg("compiled-structs.zig"); const module = self.b.createModule(.{ .root_source_file = tc_structs, }); self.structs = module; return module; } pub fn collect(self: *Compiler) !void { var cwd = std.fs.cwd(); for (self.dirs.items) |srcdir| { var idir = cwd.openDir(srcdir, .{ .iterate = true }) catch |err| { std.debug.print("template build error {} for srcdir {s}\n", .{ err, srcdir }); return err; }; defer idir.close(); var itr = idir.iterate(); while (try itr.next()) |file| { if (!std.mem.endsWith(u8, file.name, ".html")) continue; try self.collected.append(self.b.pathJoin(&[2][]const u8{ srcdir, file.name })); } } for (self.files.items) |file| { try self.collected.append(file); } } }; fn version(b: *std.Build) []const u8 { if (!std.process.can_spawn) { std.debug.print("Can't get a version number\n", .{}); std.process.exit(1); } var code: u8 = undefined; const git_wide = b.runAllowFail( &[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "describe", "--dirty", "--always", }, &code, .Ignore, ) catch @panic("git is having a bad day"); var git = std.mem.trim(u8, git_wide, " \r\n"); if (git[0] == 'v') git = git[1..]; //std.debug.print("version {s}\n", .{git}); // semver is really dumb, so we need to increment this internally var ver = std.SemanticVersion.parse(git) catch return "v0.0.0-dev"; if (ver.pre != null) { ver.minor += 1; ver.pre = std.fmt.allocPrint(b.allocator, "pre-{s}", .{ver.pre.?}) catch @panic("OOM"); } const final = std.fmt.allocPrint(b.allocator, "{}", .{ver}) catch @panic("OOM"); //std.debug.print("version {s}\n", .{final}); return final; }