build.zig (5647B)
1 const std = @import("std"); 2 const Build = std.Build; 3 const fs = std.fs; 4 const mem = std.mem; 5 6 pub fn build(b: *Build) void { 7 const enable_tests = b.option(bool, "enable-tests", "allow running tests") orelse false; 8 9 if (!enable_tests) return; 10 11 const target = b.standardTargetOptions(.{}); 12 const optimize = b.standardOptimizeOption(.{}); 13 14 const scanner = Scanner.create(b, .{}); 15 16 const wayland = b.createModule(.{ .root_source_file = scanner.result }); 17 18 scanner.generate("wl_compositor", 1); 19 scanner.generate("wl_shm", 1); 20 scanner.generate("wl_seat", 2); 21 scanner.generate("wl_output", 1); 22 23 inline for ([_][]const u8{ "globals", "list", "listener", "seats" }) |example| { 24 const exe = b.addExecutable(.{ 25 .name = example, 26 .root_source_file = b.path("example/" ++ example ++ ".zig"), 27 .target = target, 28 .optimize = optimize, 29 }); 30 31 exe.root_module.addImport("wayland", wayland); 32 exe.linkLibC(); 33 exe.linkSystemLibrary("wayland-client"); 34 35 b.installArtifact(exe); 36 } 37 38 const test_step = b.step("test", "Run the tests"); 39 { 40 const ref_all = b.addTest(.{ 41 .root_source_file = b.path("test/ref_all.zig"), 42 .target = target, 43 .optimize = optimize, 44 }); 45 46 ref_all.root_module.addImport("wayland", wayland); 47 ref_all.linkLibC(); 48 ref_all.linkSystemLibrary("wayland-client"); 49 ref_all.linkSystemLibrary("wayland-server"); 50 ref_all.linkSystemLibrary("wayland-egl"); 51 ref_all.linkSystemLibrary("wayland-cursor"); 52 53 const run_ref_all = b.addRunArtifact(ref_all); 54 test_step.dependOn(&run_ref_all.step); 55 } 56 { 57 const snapshot = b.addTest(.{ 58 .root_source_file = b.path("test/snapshot.zig"), 59 .target = target, 60 .optimize = optimize, 61 }); 62 63 const options = b.addOptions(); 64 options.addOptionPath("snapshot_actual", scanner.result); 65 66 snapshot.root_module.addOptions("build_options", options); 67 68 const run_snapshot = b.addRunArtifact(snapshot); 69 test_step.dependOn(&run_snapshot.step); 70 } 71 } 72 73 const zig_wayland_build_zig = @This(); 74 75 pub const Scanner = struct { 76 run: *Build.Step.Run, 77 result: Build.LazyPath, 78 79 wayland_protocols: Build.LazyPath, 80 81 pub const Options = struct { 82 /// Path to the wayland.xml file. 83 /// If null, the output of `pkg-config --variable=pkgdatadir wayland-scanner` will be used. 84 wayland_xml: ?Build.LazyPath = null, 85 /// Path to the wayland-protocols installation. 86 /// If null, the output of `pkg-config --variable=pkgdatadir wayland-protocols` will be used. 87 wayland_protocols: ?Build.LazyPath = null, 88 }; 89 90 pub fn create(b: *Build, options: Options) *Scanner { 91 const wayland_xml: Build.LazyPath = options.wayland_xml orelse blk: { 92 const pc_output = b.run(&.{ "pkg-config", "--variable=pkgdatadir", "wayland-scanner" }); 93 break :blk .{ 94 .cwd_relative = b.pathJoin(&.{ mem.trim(u8, pc_output, &std.ascii.whitespace), "wayland.xml" }), 95 }; 96 }; 97 const wayland_protocols: Build.LazyPath = options.wayland_protocols orelse blk: { 98 const pc_output = b.run(&.{ "pkg-config", "--variable=pkgdatadir", "wayland-protocols" }); 99 break :blk .{ 100 .cwd_relative = mem.trim(u8, pc_output, &std.ascii.whitespace), 101 }; 102 }; 103 104 const exe = b.addExecutable(.{ 105 .name = "zig-wayland-scanner", 106 .root_source_file = if (b.available_deps.len > 0) 107 b.dependencyFromBuildZig(zig_wayland_build_zig, .{}).path("src/scanner.zig") 108 else 109 b.path("src/scanner.zig"), 110 .target = b.graph.host, 111 }); 112 113 const run = b.addRunArtifact(exe); 114 115 run.addArg("-o"); 116 const result = run.addOutputFileArg("wayland.zig"); 117 118 run.addArg("-i"); 119 run.addFileArg(wayland_xml); 120 121 const scanner = b.allocator.create(Scanner) catch @panic("OOM"); 122 scanner.* = .{ 123 .run = run, 124 .result = result, 125 .wayland_protocols = wayland_protocols, 126 }; 127 128 return scanner; 129 } 130 131 /// Scan protocol xml provided by the wayland-protocols package at the given path 132 /// relative to the wayland-protocols installation. (e.g. "stable/xdg-shell/xdg-shell.xml") 133 pub fn addSystemProtocol(scanner: *Scanner, sub_path: []const u8) void { 134 const b = scanner.run.step.owner; 135 136 scanner.run.addArg("-i"); 137 scanner.run.addFileArg(scanner.wayland_protocols.path(b, sub_path)); 138 } 139 140 /// Scan the protocol xml at the given path. 141 pub fn addCustomProtocol(scanner: *Scanner, path: Build.LazyPath) void { 142 scanner.run.addArg("-i"); 143 scanner.run.addFileArg(path); 144 } 145 146 /// Generate code for the given global interface at the given version, 147 /// as well as all interfaces that can be created using it at that version. 148 /// If the version found in the protocol xml is less than the requested version, 149 /// an error will be printed and code generation will fail. 150 /// Code is always generated for wl_display, wl_registry, wl_callback, and wl_buffer. 151 pub fn generate(scanner: *Scanner, global_interface: []const u8, version: u32) void { 152 var buffer: [32]u8 = undefined; 153 const version_str = std.fmt.bufPrint(&buffer, "{}", .{version}) catch unreachable; 154 155 scanner.run.addArgs(&.{ "-g", global_interface, version_str }); 156 } 157 };