-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.zig
More file actions
220 lines (189 loc) · 9.11 KB
/
Copy pathbuild.zig
File metadata and controls
220 lines (189 loc) · 9.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
const std = @import("std");
const phx = @import("src/phoenix.zig");
pub fn build(b: *std.Build) !void {
const backends_option = b.option([]const u8, "backends",
\\Select which backends to include in the build ("all", "x11", "wayland", "drm"). This is a comma-separated list. Defaults to "all"
) orelse "all";
const backends = try backends_from_string_list(backends_option);
if (!backends.x11 and !backends.wayland and !backends.drm) {
std.log.err("Expected at least one backend (-Dbackends) to be specified", .{});
return error.MissingBackendOption;
}
const generate_docs_option = b.option(bool, "generate-docs", "Generate X11 protocol documentation") orelse false;
if (generate_docs_option) {
try generate_docs(b.install_path);
return;
}
const debugger = b.option(bool, "debugger", "Build with debugger support") orelse false;
const target = b.standardTargetOptions(.{});
const optimize = if (debugger) .Debug else b.standardOptimizeOption(.{});
const exe_mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.strip = optimize != .Debug,
// .single_threaded = true,
});
const config = b.addOptions();
config.addOption(Backends, "backends", backends);
exe_mod.addOptions("config", config);
const exe = b.addExecutable(.{
.name = "phoenix",
.root_module = exe_mod,
// Needed to make debug symbols work correctly in debug mode at the moment (zig 0.15.2) without having to use a fork of lldb (https://codeberg.org/ziglang/zig#testing-zig-code-with-lldb)
.use_lld = if (debugger) true else null,
.use_llvm = if (debugger) true else null,
});
b.installArtifact(exe);
exe.root_module.linkSystemLibrary("xkbcommon", .{});
if (backends.x11) {
// TODO: Remove this, we can just use our existing X11 code to connect to the X server directly
exe.root_module.linkSystemLibrary("xcb", .{});
exe.root_module.linkSystemLibrary("xcb-xkb", .{});
}
if (backends.wayland) {
exe.root_module.linkSystemLibrary("wayland-client", .{});
exe.root_module.linkSystemLibrary("wayland-egl", .{});
}
if (backends.drm) {
// TODO: Use ioctl directly instead of depending on these
exe.root_module.linkSystemLibrary("libdrm", .{});
exe.root_module.linkSystemLibrary("gbm", .{});
}
exe.root_module.linkSystemLibrary("gl", .{});
exe.root_module.linkSystemLibrary("egl", .{});
const check = b.step("check", "Check if Phoenix compiles");
check.dependOn(&exe.step);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const exe_unit_tests = b.addTest(.{
.root_module = exe.root_module,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_exe_unit_tests.step);
}
fn backends_from_string_list(backends: []const u8) !Backends {
var result = Backends{
.x11 = false,
.wayland = false,
.drm = false,
};
var it = std.mem.splitScalar(u8, backends, ',');
while (it.next()) |backend| {
if (std.mem.eql(u8, backend, "all")) {
result.x11 = true;
result.wayland = true;
result.drm = true;
} else if (std.mem.eql(u8, backend, "x11")) {
result.x11 = true;
} else if (std.mem.eql(u8, backend, "wayland")) {
result.wayland = true;
} else if (std.mem.eql(u8, backend, "drm")) {
result.drm = true;
} else {
std.log.err("Option \"{s}\" is invalid for -Dbackends, expected \"all\", \"x11\", \"wayland\" or \"drm\"", .{backend});
return error.InvalidBackendOption;
}
}
return result;
}
fn generate_docs(install_path: []const u8) !void {
var install_path_dir = try std.fs.openDirAbsolute(install_path, .{});
defer install_path_dir.close();
install_path_dir.makeDir("protocol") catch |err| switch (err) {
error.PathAlreadyExists => {},
else => return err,
};
@setEvalBranchQuota(9000);
try generate_protocol_docs(phx.ConnectionSetup, &install_path_dir);
try generate_protocol_docs(phx.core, &install_path_dir);
try generate_protocol_docs(phx.Dri3, &install_path_dir);
try generate_protocol_docs(phx.Glx, &install_path_dir);
try generate_protocol_docs(phx.Present, &install_path_dir);
try generate_protocol_docs(phx.Randr, &install_path_dir);
try generate_protocol_docs(phx.Render, &install_path_dir);
try generate_protocol_docs(phx.Sync, &install_path_dir);
try generate_protocol_docs(phx.Xfixes, &install_path_dir);
try generate_protocol_docs(phx.Xkb, &install_path_dir);
try generate_protocol_docs(phx.GenericEvent, &install_path_dir);
try generate_protocol_docs(phx.MitShm, &install_path_dir);
// TODO: Also generate replies, errors and events (including phx.event.Event)
}
fn generate_protocol_docs(comptime file_struct: type, install_path_dir: *std.fs.Dir) !void {
const filename = type_get_name_only(@typeName(file_struct));
var filepath_buf: [256]u8 = undefined;
const filepath = std.fmt.bufPrint(&filepath_buf, "protocol/{s}.txt", .{filename}) catch unreachable;
const file = try install_path_dir.createFile(filepath, .{});
defer file.close();
var file_buffer: [4096]u8 = undefined;
var writer = file.writer(&file_buffer);
var file_out = &writer.interface;
try file_out.print("Requests\n", .{});
inline for (@typeInfo(file_struct.Request).@"struct".decls) |decl| {
const request_type = @field(file_struct.Request, decl.name);
if (comptime std.meta.activeTag(@typeInfo(request_type)) != .@"struct")
continue;
try file_out.print("{s}\n", .{type_get_name_only(@typeName(request_type))});
inline for (@typeInfo(request_type).@"struct".fields) |field| {
switch (@typeInfo(field.type)) {
.@"struct" => {
// TODO: Handle UnionList
if (@hasDecl(field.type, "is_list_of")) {
const field_value = comptime "ListOf" ++ type_get_name_only(@typeName(field.type.get_element_type()));
const list_options = field.type.get_options();
try file_out.print(" {s: <14} {s: <10} {s}\n", .{ list_options.length_field orelse "", field_value, field.name });
} else if (field.type == phx.x11.AlignmentPadding) {
try file_out.print(" {s: <14} {s: <10} p=padding\n", .{ "p", "" });
} else {
const field_value = type_get_name_only(@typeName(field.type));
try file_out.print(" {d: <14} {s: <10} {s}\n", .{ @sizeOf(field.type), field_value, field.name });
}
},
.@"enum" => |*e| {
const field_type_name = comptime type_get_name_only(@typeName(field.type));
const field_value = if (field.defaultValue()) |default_value| default_value else field_type_name;
if (field.type == phx.opcode.Major or comptime std.mem.eql(u8, field_type_name, "MinorOpcode")) {
try file_out.print(" {d: <14} {d: <10} {s}\n", .{ @sizeOf(field.type), @intFromEnum(field_value), field.name });
} else if (!e.is_exhaustive) {
try file_out.print(" {d: <14} {s: <10} {s}\n", .{ @sizeOf(field.type), type_get_name_only(@typeName(field.type)), field.name });
} else {
try file_out.print(" {d: <14} {s: <10} {s}\n", .{ @sizeOf(field.type), "", field.name });
inline for (e.fields) |enum_field| {
try file_out.print(" {d: <3} {s}\n", .{ enum_field.value, enum_field.name });
}
}
},
else => {
const type_name = switch (field.type) {
u8 => "CARD8",
u16 => "CARD16",
u32 => "CARD32",
u64 => "CARD64",
bool => "BOOL",
i16 => "INT16",
else => type_get_name_only(@typeName(field.type)),
};
try file_out.print(" {d: <14} {s: <10} {s}\n", .{ @sizeOf(field.type), type_name, field.name });
},
}
}
try file_out.print("\n", .{});
}
try file_out.flush();
}
fn type_get_name_only(type_name: []const u8) []const u8 {
const index = std.mem.lastIndexOfScalar(u8, type_name, '.') orelse return type_name;
return type_name[index + 1 ..];
}
const Backends = struct {
x11: bool,
wayland: bool,
drm: bool,
};