Skip to content

Commit

Permalink
scanner: require explicit target globals/versions
Browse files Browse the repository at this point in the history
Now only wl_display, wl_registry, and wl_callback are generated by
default (these interfaces are locked to version 1 for eternity).

All other interfaces must be explicitly requested in the program's
build.zig using ScanProtocolsStep.generate(global_name, version).

This ensures forwards compatibility of programs written using
zig-wayland with newer protocol xml.
  • Loading branch information
ifreund committed May 10, 2022
1 parent 003984f commit c9b8c0c
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 59 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,19 @@ pub fn build(b: *Builder) void {
const scanner = ScanProtocolsStep.create(b);
scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml");
scanner.addProtocolPath("protocol/foobar.xml");
scanner.addSystemProtocol("staging/ext-session-lock/ext-session-lock-v1.xml");
scanner.addProtocolPath("protocol/private_foobar.xml");
// Pass the maximum version implemented by your wayland server or client.
// Requests, events, enums, etc. from newer versions will not be generated,
// ensuring forwards compatibility with newer protocol xml.
// This will also generate code for interfaces created using the provided
// global interface, in this example wl_keyboard, wl_pointer, xdg_surface,
// xdg_toplevel, etc. would be generated.
scanner.generate("wl_seat", 4);
scanner.generate("xdg_wm_base", 3);
scanner.generate("ext_session_lock_manager_v1", 1);
scanner.generate("private_foobar_manager", 1);
const exe = b.addExecutable("foo", "foo.zig");
exe.setTarget(target);
Expand Down
23 changes: 20 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ pub fn build(b: *zbs.Builder) void {
.path = .{ .generated = &scanner.result },
};

scanner.generate("wl_compositor", 1);
scanner.generate("wl_shm", 1);
scanner.generate("wl_seat", 2);
scanner.generate("wl_output", 1);

inline for ([_][]const u8{ "globals", "list", "listener", "seats" }) |example| {
const exe = b.addExecutable(example, "example/" ++ example ++ ".zig");
exe.setTarget(target);
Expand Down Expand Up @@ -64,6 +69,7 @@ pub const ScanProtocolsStep = struct {

/// Slice of absolute paths of protocol xml files to be scanned
protocol_paths: std.ArrayList([]const u8),
targets: std.ArrayList(scanner.Target),

pub fn create(builder: *zbs.Builder) *ScanProtocolsStep {
const ally = builder.allocator;
Expand All @@ -73,16 +79,18 @@ pub const ScanProtocolsStep = struct {
.step = zbs.Step.init(.custom, "Scan Protocols", ally, make),
.result = .{ .step = &self.step, .path = null },
.protocol_paths = std.ArrayList([]const u8).init(ally),
.targets = std.ArrayList(scanner.Target).init(ally),
};
self.targets.append(.{ .name = "wl_display", .version = 1 }) catch unreachable;
return self;
}

/// Generate bindings from the protocol xml at the given absolute or relative path
/// Scan the protocol xml at the given absolute or relative path
pub fn addProtocolPath(self: *ScanProtocolsStep, path: []const u8) void {
self.protocol_paths.append(path) catch unreachable;
}

/// Generate bindings from protocol xml provided by the wayland-protocols
/// Scan the protocol xml provided by the wayland-protocols
/// package given the relative path (e.g. "stable/xdg-shell/xdg-shell.xml")
pub fn addSystemProtocol(self: *ScanProtocolsStep, relative_path: []const u8) void {
const protocol_dir = mem.trim(u8, self.builder.exec(
Expand All @@ -94,6 +102,15 @@ pub const ScanProtocolsStep = struct {
) catch unreachable);
}

/// Generate code for the given global interface at the given version,
/// as well as all interfaces that can be created using it at that version.
/// If the version found in the protocol xml is less than the requested version,
/// an error will be printed and code generation will fail.
/// Code is always generated for wl_display, wl_registry, and wl_callback.
pub fn generate(self: *ScanProtocolsStep, global_interface: []const u8, version: u32) void {
self.targets.append(.{ .name = global_interface, .version = version }) catch unreachable;
}

fn make(step: *zbs.Step) !void {
const self = @fieldParentPtr(ScanProtocolsStep, "step", step);
const ally = self.builder.allocator;
Expand All @@ -109,7 +126,7 @@ pub const ScanProtocolsStep = struct {
defer root_dir.close();
var out_dir = try root_dir.makeOpenPath(out_path, .{});
defer out_dir.close();
try scanner.scan(root_dir, out_dir, wayland_xml, self.protocol_paths.items);
try scanner.scan(root_dir, out_dir, wayland_xml, self.protocol_paths.items, self.targets.items);

// Once https://github.com/ziglang/zig/issues/131 is implemented
// we can stop generating/linking C code.
Expand Down

0 comments on commit c9b8c0c

Please sign in to comment.