build.zig 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. const std = @import("std");
  2. const Build = std.Build;
  3. // TODO: get version from `build.zig.zon`
  4. const VERSION = std.SemanticVersion.parse("0.0.2") catch unreachable;
  5. const BuildCtx = struct {
  6. const Self = @This();
  7. const NamedExe = struct {
  8. name: []const u8,
  9. exe: *Build.Step.Compile,
  10. };
  11. build: *Build,
  12. modules: []*Build.Module,
  13. target: Build.ResolvedTarget,
  14. optimize: std.builtin.Mode,
  15. bin_path: []const u8,
  16. lib_path: []const u8,
  17. fn init(b: *Build) !Self {
  18. const lib_path = b.pathJoin(&.{ "src", "lib.zig" });
  19. return .{
  20. .build = b,
  21. .modules = blk: {
  22. var modules = std.ArrayList(*Build.Module).init(b.allocator);
  23. const clap =
  24. b.dependency("clap", .{}).module("clap");
  25. const lib = b.createModule(.{
  26. .root_source_file = b.path(lib_path),
  27. .imports = &.{.{ .name = "clap", .module = clap }},
  28. });
  29. try modules.appendSlice(&.{
  30. lib,
  31. clap,
  32. });
  33. break :blk try modules.toOwnedSlice();
  34. },
  35. .target = b.standardTargetOptions(.{}),
  36. .optimize = b.standardOptimizeOption(.{
  37. .preferred_optimize_mode = .ReleaseFast,
  38. }),
  39. .bin_path = b.pathJoin(&.{ "src", "bin" }),
  40. .lib_path = lib_path,
  41. };
  42. }
  43. fn add_run_step(self: Self, exe: Self.NamedExe) !void {
  44. var buf: [std.fs.MAX_NAME_BYTES * 4]u8 = undefined;
  45. var fba = std.heap.FixedBufferAllocator.init(&buf);
  46. const allocator = fba.allocator();
  47. const step = try std.mem.join(allocator, ":", &.{ "run", exe.name });
  48. const desc = try std.fmt.allocPrint(allocator, "Run command: `{s}`", .{exe.name});
  49. const b = self.build;
  50. const run_cmd = b.addRunArtifact(exe.exe);
  51. run_cmd.step.dependOn(b.getInstallStep());
  52. if (b.args) |args| {
  53. run_cmd.addArgs(args);
  54. }
  55. const run_step = b.step(step, desc);
  56. run_step.dependOn(&run_cmd.step);
  57. }
  58. fn do_exe(self: Self) !void {
  59. const b = self.build;
  60. const dir = try b.build_root.handle.openDir(self.bin_path, .{ .iterate = true });
  61. var it = dir.iterate();
  62. const exe_opts = b.addOptions();
  63. exe_opts.addOption(std.SemanticVersion, "version", VERSION);
  64. while (try it.next()) |bin| {
  65. const name = bin.name;
  66. if (std.mem.eql(u8, ".zig", std.fs.path.extension(name))) {
  67. const exe_name = std.fs.path.stem(name);
  68. const exe = b.addExecutable(.{
  69. .name = exe_name,
  70. .root_source_file = b.path(b.pathJoin(&.{ self.bin_path, name })),
  71. .target = self.target,
  72. .optimize = self.optimize,
  73. });
  74. exe.root_module.addOptions("build_options", exe_opts);
  75. for (self.modules) |mod| {
  76. const mod_name = std.fs.path.stem(mod.root_source_file.?.getDisplayName());
  77. exe.root_module.addImport(mod_name, mod);
  78. }
  79. b.installArtifact(exe);
  80. try self.add_run_step(.{ .name = exe_name, .exe = exe });
  81. }
  82. }
  83. }
  84. fn do_test(self: Self) !void {
  85. const b = self.build;
  86. const unit_tests = b.addTest(.{
  87. .root_source_file = b.path(self.lib_path),
  88. .target = self.target,
  89. .optimize = self.optimize,
  90. });
  91. const run_unit_tests = b.addRunArtifact(unit_tests);
  92. const test_step = b.step("test", "Run unit tests");
  93. test_step.dependOn(&run_unit_tests.step);
  94. }
  95. };
  96. pub fn build(b: *Build) !void {
  97. const ctx = try BuildCtx.init(b);
  98. try ctx.do_exe();
  99. try ctx.do_test();
  100. }