From 3bad0e822b805906d3310900cd27e71ad19818fd Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Mon, 1 Sep 2025 15:08:04 -0400 Subject: [PATCH 01/12] fix: start working on build.zig --- .gitignore | 2 +- .gitmodules | 6 + build.zig | 503 ++++++------------------------------------- build.zig.zon | 14 +- external/libxau.zig | 1 + external/zig-clap | 1 + lib/xcb/protocol.zig | 2 +- 7 files changed, 82 insertions(+), 447 deletions(-) create mode 100644 .gitmodules create mode 160000 external/libxau.zig create mode 160000 external/zig-clap diff --git a/.gitignore b/.gitignore index 4c82b07..d8c8979 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -zig-cache +.zig-cache zig-out diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..802fa7d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "external/libxau.zig"] + path = external/libxau.zig + url = https://github.com/PaNDa2code/libxau_zig +[submodule "external/zig-clap"] + path = external/zig-clap + url = https://github.com/Hejsil/zig-clap diff --git a/build.zig b/build.zig index 6e578fc..6b3acd6 100644 --- a/build.zig +++ b/build.zig @@ -1,469 +1,96 @@ const std = @import("std"); -const assert = std.debug.assert; +const Build = std.Build; pub const Protocol = @import("lib/xcb/protocol.zig"); -const LinkMode = if (@hasField(std.builtin.LinkMode, "static")) std.builtin.LinkMode else std.Build.Step.Compile.Linkage; - -fn runAllowFail( - self: *std.Build, - argv: []const []const u8, - cwd: []const u8, - out_code: *u8, - stderr_behavior: std.ChildProcess.StdIo, -) std.Build.RunError![]u8 { - assert(argv.len != 0); - - if (!std.process.can_spawn) - return error.ExecNotSupported; - - const max_output_size = 400 * 1024; - var child = std.ChildProcess.init(argv, self.allocator); - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Pipe; - child.stderr_behavior = stderr_behavior; - child.env_map = &self.graph.env_map; - child.cwd = cwd; - - try child.spawn(); - - const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch { - return error.ReadFailure; - }; - errdefer self.allocator.free(stdout); - - const term = try child.wait(); - switch (term) { - .Exited => |code| { - if (code != 0) { - out_code.* = @as(u8, @truncate(code)); - return error.ExitCodeFailure; - } - return stdout; - }, - .Signal, .Stopped, .Unknown => |code| { - out_code.* = @as(u8, @truncate(code)); - return error.ProcessTerminated; - }, - } -} - -fn run(b: *std.Build, argv: []const []const u8, cwd: []const u8) []u8 { - if (!std.process.can_spawn) { - std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}\n", .{ - try std.Build.Step.allocPrintCmd(b.allocator, null, argv), - }); - std.process.exit(1); - } - - var code: u8 = undefined; - return runAllowFail(b, argv, cwd, &code, .Inherit) catch |err| { - const printed_cmd = std.Build.Step.allocPrintCmd(b.allocator, null, argv) catch @panic("OOM"); - std.debug.print("unable to spawn the following command: {s}\n{s}\n", .{ - @errorName(err), printed_cmd, - }); - std.process.exit(1); - }; -} - pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const no_docs = b.option(bool, "no-docs", "skip installing documentation") orelse false; - const linkage = b.option(LinkMode, "linkage", "whether to statically or dynamically link the library") orelse @as(LinkMode, if (target.result.isGnuLibC()) .dynamic else .static); + const linkage: std.builtin.LinkMode = + b.option(std.builtin.LinkMode, "linkage", "whether to statically or dynamically link the library") orelse + if (target.result.isGnuLibC()) + .dynamic + else + .static; const clap = b.dependency("clap", .{ .target = target, .optimize = optimize, }); - const libxcbSource = b.dependency("libxcb", .{}); - const xcbprotoSource = b.dependency("xcbproto", .{}); + const libxcb_upstream = b.dependency("libxcb", .{}); + const xcbproto_upstream = b.dependency("xcbproto", .{}); const libxau = b.dependency("libxau", .{ .target = target, .optimize = optimize, .linkage = linkage, }); - const libxauSource = libxau.builder.dependency("libxau", .{}); - const xorgprotoSource = libxau.builder.dependency("xorgproto", .{}); - - const xcbUtilSource = b.dependency("xcb-util", .{}); - const xcbUtilImageSource = b.dependency("xcb-util-image", .{}); - - const python3 = try b.findProgram(&.{ "python3", "python" }, &.{}); - - const headers = b.addWriteFiles(); - var protoCSources = std.ArrayList([]const u8).init(b.allocator); - - const xcbprotoPath = blk: { - var man = b.graph.cache.obtain(); - defer man.deinit(); - - const xcbprotoSourcePath = xcbprotoSource.path("src").getPath(xcbprotoSource.builder); - man.hash.addBytes(xcbprotoSourcePath); - - var dir = try std.fs.openDirAbsolute(xcbprotoSourcePath, .{ .iterate = true }); - defer dir.close(); - - var iter = dir.iterate(); - while (try iter.next()) |entry| { - if (!std.mem.endsWith(u8, entry.name, ".xml")) continue; - - _ = try man.addFile(xcbprotoSource.path(try std.fs.path.join(b.allocator, &.{ "src", entry.name })).getPath(xcbprotoSource.builder), null); - } - - if (!(try man.hit())) { - const digest = man.final(); - const cachePath = try b.cache_root.join(b.allocator, &.{ "o", &digest }); - - try b.cache_root.handle.makeDir(try std.fs.path.join(b.allocator, &.{ "o", &digest })); - - iter = dir.iterate(); - while (try iter.next()) |entry| { - if (!std.mem.endsWith(u8, entry.name, ".xml")) continue; - - _ = run(b, &.{ - python3, - libxcbSource.path("src/c_client.py").getPath(xcbprotoSource.builder), - "-c", - "libxcb", - "-l", - "libxcb", - "-s", - "3", - "-p", - xcbprotoSource.path(".").getPath(xcbprotoSource.builder), - xcbprotoSource.path(try std.fs.path.join(b.allocator, &.{ "src", entry.name })).getPath(xcbprotoSource.builder), - }, cachePath); - - const header = b.fmt("{s}.h", .{entry.name[0..(entry.name.len - 4)]}); - - _ = headers.addCopyFile(.{ - .path = try std.fs.path.join(b.allocator, &.{ cachePath, header }), - }, try std.fs.path.join(b.allocator, &.{ "xcb", header })); - - try protoCSources.append(b.fmt("{s}.c", .{ - entry.name[0..(entry.name.len - 4)], - })); - } - - try man.writeManifest(); - - break :blk cachePath; - } else { - const digest = man.final(); - const cachePath = try b.cache_root.join(b.allocator, &.{ "o", &digest }); - - iter = dir.iterate(); - while (try iter.next()) |entry| { - if (!std.mem.endsWith(u8, entry.name, ".xml")) continue; - - const header = b.fmt("{s}.h", .{entry.name[0..(entry.name.len - 4)]}); - - _ = headers.addCopyFile(.{ - .path = try std.fs.path.join(b.allocator, &.{ cachePath, header }), - }, try std.fs.path.join(b.allocator, &.{ "xcb", header })); - - try protoCSources.append(b.fmt("{s}.c", .{ - entry.name[0..(entry.name.len - 4)], - })); - } - - break :blk try b.cache_root.join(b.allocator, &.{ "o", &digest }); - } - }; - - { - var dir = try std.fs.openDirAbsolute(xorgprotoSource.path("include").getPath(xorgprotoSource.builder), .{ .iterate = true }); - defer dir.close(); - - var iter = try dir.walk(b.allocator); - defer iter.deinit(); - - while (try iter.next()) |entry| { - if (std.mem.eql(u8, entry.basename, "meson.build")) continue; - if (entry.kind != .file) continue; - - _ = headers.addCopyFile(xorgprotoSource.path(try std.fs.path.join(b.allocator, &.{ "include", entry.path })), entry.path); - } - } - - _ = headers.addCopyFile(libxcbSource.path("src/xcb.h"), "xcb/xcb.h"); - _ = headers.addCopyFile(xcbUtilSource.path("src/xcb_atom.h"), "xcb/xcb_atom.h"); - _ = headers.addCopyFile(xcbUtilSource.path("src/xcb_aux.h"), "xcb/xcb_aux.h"); - _ = headers.addCopyFile(xcbUtilSource.path("src/xcb_event.h"), "xcb/xcb_event.h"); - _ = headers.addCopyFile(xcbUtilSource.path("src/xcb_util.h"), "xcb/xcb_util.h"); - _ = headers.addCopyFile(xcbUtilImageSource.path("image/xcb_bitops.h"), "xcb/xcb_bitops.h"); - _ = headers.addCopyFile(xcbUtilImageSource.path("image/xcb_image.h"), "xcb/xcb_image.h"); - _ = headers.addCopyFile(xcbUtilImageSource.path("image/xcb_pixel.h"), "xcb/xcb_pixel.h"); - - const libxcb = std.Build.Step.Compile.create(b, .{ - .name = "xcb", - .root_module = .{ - .target = target, - .optimize = optimize, - .link_libc = true, - }, - .kind = .lib, - .linkage = linkage, - }); - - for (headers.files.items) |header| { - const install_file = b.addInstallFileWithDir(header.getPath(), .header, header.sub_path); - b.getInstallStep().dependOn(&install_file.step); - libxcb.installed_headers.append(&install_file.step) catch @panic("OOM"); - } - - libxcb.addIncludePath(libxcbSource.path("src")); - libxcb.addIncludePath(libxauSource.path("include")); - libxcb.addIncludePath(xorgprotoSource.path("include")); - libxcb.addIncludePath(.{ .path = xcbprotoPath }); - - libxcb.addCSourceFiles(.{ - .root = libxcbSource.path("."), - .files = &.{ - "src/xcb_auth.c", - "src/xcb_conn.c", - "src/xcb_ext.c", - "src/xcb_in.c", - "src/xcb_list.c", - "src/xcb_out.c", - "src/xcb_util.c", - "src/xcb_xid.c", - }, - .flags = &.{ - "-DXCB_QUEUE_BUFFER_SIZE=16384", - "-DIOV_MAX=16", - }, - }); - - libxcb.addCSourceFiles(.{ - .root = .{ .path = xcbprotoPath }, - .files = protoCSources.items, - .flags = &.{ - "-DXCB_QUEUE_BUFFER_SIZE=16384", - "-DIOV_MAX=16", - }, - }); - - libxcb.linkLibrary(libxau.artifact("Xau")); - b.installArtifact(libxcb); - - const libxcbShm = std.Build.Step.Compile.create(b, .{ - .name = "xcb-shm", - .root_module = .{ - .target = target, - .optimize = optimize, - .link_libc = true, - }, - .kind = .lib, - .linkage = linkage, - }); - - libxcbShm.addIncludePath(libxcbSource.path("src")); - libxcbShm.addIncludePath(libxauSource.path("include")); - libxcbShm.addIncludePath(xorgprotoSource.path("include")); - libxcbShm.addIncludePath(.{ .path = xcbprotoPath }); - - libxcbShm.addCSourceFiles(.{ - .root = .{ .path = xcbprotoPath }, - .files = &.{ "shm.c", "xinerama.c" }, - }); - - libxcbShm.linkLibrary(libxcb); - b.installArtifact(libxcbShm); - - const xcbutil = std.Build.Step.Compile.create(b, .{ - .name = "xcb-util", - .root_module = .{ - .target = target, - .optimize = optimize, - .link_libc = true, - }, - .kind = .lib, - .linkage = linkage, - }); - - xcbutil.addIncludePath(headers.getDirectory()); - - xcbutil.addCSourceFiles(.{ - .root = xcbUtilSource.path("src"), - .files = &.{ - "atoms.c", - "event.c", - "xcb_aux.c", - }, - }); - - b.installArtifact(xcbutil); - - const xcbutilImage = std.Build.Step.Compile.create(b, .{ - .name = "xcb-image", - .root_module = .{ - .target = target, - .optimize = optimize, - .link_libc = true, - }, - .kind = .lib, - .linkage = linkage, - }); - - xcbutilImage.addIncludePath(headers.getDirectory()); - - xcbutilImage.addCSourceFiles(.{ - .root = xcbUtilImageSource.path("image"), - .files = &.{ - "xcb_image.c", - }, - }); - - xcbutilImage.linkLibrary(xcbutil); - xcbutilImage.linkLibrary(libxcbShm); - b.installArtifact(xcbutilImage); - - const bootstrapOptions = b.addOptions(); - bootstrapOptions.addOption([]const u8, "importName", "../xcb.zig"); - const options = b.addOptions(); - options.addOption([]const u8, "importName", "xcb"); + const libxau_upstream = libxau.builder.dependency("libxau", .{}); + const xorgproto_upstream = libxau.builder.dependency("xorgproto", .{}); - const moduleSource = b.addWriteFiles(); - { - const protogen = b.addExecutable(.{ - .name = "protogen", - .root_source_file = .{ - .path = b.pathFromRoot("bin/protogen.zig"), - }, - .target = b.host, - .optimize = optimize, - .linkage = linkage, - }); + const xcb_util_upstream = b.dependency("xcb-util", .{}); + const xcb_util_image_upstream = b.dependency("xcb-util-image", .{}); - protogen.root_module.addImport("clap", clap.module("clap")); - protogen.root_module.addAnonymousImport("xcb", .{ - .root_source_file = .{ - .path = b.pathFromRoot("lib/xcb.zig"), - }, - .target = b.host, - .optimize = optimize, - .imports = &.{ - .{ - .name = "options", - .module = bootstrapOptions.createModule(), - }, - }, - }); + const python3_path = try b.findProgram(&.{ "python3", "python" }, &.{}); - const protogenRun = b.addRunArtifact(protogen); - protogenRun.addDirectoryArg(xcbprotoSource.path("src")); - protogenRun.addArgs(&.{ "-g", "zig" }); - _ = moduleSource.addCopyFile(protogenRun.captureStdOut(), "xcb/protos.zig"); - } + var xproto_c_sources = try std.ArrayList(Build.LazyPath).initCapacity(b.allocator, 0); - { - var dir = try std.fs.openDirAbsolute(b.pathFromRoot("lib"), .{ .iterate = true }); - defer dir.close(); - - var iter = try dir.walk(b.allocator); - defer iter.deinit(); - - while (try iter.next()) |entry| { - if (entry.kind != .file) continue; - if (std.mem.eql(u8, entry.path, "xcb/protos.zig")) continue; - - _ = moduleSource.addCopyFile(.{ - .path = b.pathFromRoot(try std.fs.path.join(b.allocator, &.{ "lib", entry.path })), - }, entry.path); - } - } - - const module = b.addModule("xcb", .{ - .root_source_file = blk: { - for (moduleSource.files.items) |item| { - if (std.mem.eql(u8, item.sub_path, "xcb.zig")) { - break :blk item.getPath(); - } - } - unreachable; - }, + const libxcb_mod = b.createModule(.{ .target = target, .optimize = optimize, - .link_libc = true, }); - - module.addImport("options", options.createModule()); - - module.addIncludePath(headers.getDirectory()); - module.linkLibrary(libxcb); - module.linkLibrary(xcbutilImage); - - const step_test = b.step("test", "Run all unit tests"); - - const unit_tests = b.addTest(.{ - .root_source_file = module.root_source_file.?, - .target = target, - .optimize = optimize, - .link_libc = true, - }); - - unit_tests.root_module.addImport("options", bootstrapOptions.createModule()); - - unit_tests.addIncludePath(headers.getDirectory()); - unit_tests.linkLibrary(libxcb); - unit_tests.linkLibrary(xcbutilImage); - - const run_unit_tests = b.addRunArtifact(unit_tests); - step_test.dependOn(&run_unit_tests.step); - - if (!no_docs) { - const docs = b.addInstallDirectory(.{ - .source_dir = unit_tests.getEmittedDocs(), - .install_dir = .prefix, - .install_subdir = "docs", - }); - - b.getInstallStep().dependOn(&docs.step); - } - - const example = b.addExecutable(.{ - .name = "example", - .root_source_file = .{ - .path = b.pathFromRoot("example.zig"), - }, - .target = target, - .optimize = optimize, - .link_libc = true, - .linkage = linkage, + const libxcb = b.addLibrary(.{ + .name = "libxcb", + .root_module = libxcb_mod, }); - example.root_module.addImport("xcb", module); - b.installArtifact(example); - - const protogen = b.addExecutable(.{ - .name = "protogen", - .root_source_file = .{ - .path = b.pathFromRoot("bin/protogen.zig"), - }, - .target = target, - .optimize = optimize, - .linkage = linkage, - }); - - protogen.root_module.addImport("clap", clap.module("clap")); - - protogen.root_module.addAnonymousImport("xcb", .{ - .root_source_file = .{ - .path = b.pathFromRoot("lib/xcb.zig"), - }, - .target = target, - .optimize = optimize, - .imports = &.{ - .{ - .name = "options", - .module = options.createModule(), - }, - }, - }); - b.installArtifact(protogen); + const xcb_proto_path = blk: { + for (xml_files) |xml_file| { + const cmd = b.addSystemCommand(&.{python3_path}); + cmd.addFileArg(libxcb_upstream.path("src/c_client.py")); + cmd.addArgs(&.{ "-c", "libxcb", "-l", "libxcb", "-s", "3", "-p" }); + cmd.addDirectoryArg(xcbproto_upstream.path(".")); + cmd.addFileArg(xcbproto_upstream.path(".")); + cmd.addFileArg(xcbproto_upstream.path(b.fmt("src/{s}", .{xml_file}))); + } + }; } + +const xml_files = [_][]const u8{ + "xcb.xsd", + "xproto.xml", + "bigreq.xml", + "composite.xml", + "damage.xml", + "dbe.xml", + "dpms.xml", + "dri2.xml", + "dri3.xml", + "ge.xml", + "glx.xml", + "present.xml", + "randr.xml", + "record.xml", + "render.xml", + "res.xml", + "screensaver.xml", + "shape.xml", + "shm.xml", + "sync.xml", + "xc_misc.xml", + "xevie.xml", + "xf86dri.xml", + "xf86vidmode.xml", + "xfixes.xml", + "xinerama.xml", + "xinput.xml", + "xkb.xml", + "xprint.xml", + "xselinux.xml", + "xtest.xml", + "xv.xml", + "xvmc.xml", +}; diff --git a/build.zig.zon b/build.zig.zon index e0b05f7..7aac606 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,5 +1,6 @@ .{ - .name = "xcb.zig", + .name = .xcb, + .fingerprint = 0x48cfd8eae06c78ea, .version = "0.1.16", .paths = .{""}, .dependencies = .{ @@ -11,10 +12,6 @@ .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.16.0/xcbproto-xcb-proto-1.16.0.tar.gz", .hash = "122088858bfa13f990603440f3b13aa027abfa828de875497fcb58efd017fe0af6ea", }, - .libxau = .{ - .url = "https://github.com/MidstallSoftware/libxau.zig/archive/a8adbbd1a687cb460dcb0356b973c740d6dc4c36.tar.gz", - .hash = "1220a0ccc00ff9ee2df9ae313345dd93af2a8876772f127e8bc5c90eca7bd2547c34", - }, .@"xcb-util" = .{ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb-util/-/archive/xcb-util-0.4.1/libxcb-util-xcb-util-0.4.1.tar.gz", .hash = "1220096cb9b583a14b307609801d8a018a3babc9e608170afc521a0db4e437165c15", @@ -23,9 +20,12 @@ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb-image/-/archive/xcb-util-image-0.4.1/libxcb-image-xcb-util-image-0.4.1.tar.gz", .hash = "122092beed2990a3b55f6ad7984159e2e53ef2372ecd36d95deeda007ee3903a6797", }, + .clap = .{ - .url = "https://github.com/MidstallSoftware/zig-clap/archive/2f0b4443b2a168e2ee545e595b104a9900bc3401.tar.gz", - .hash = "12201e606115ddfe830f1a585919bdebe27d2217114d05b03b617fc0f274218514d3", + .path = "./external/zig-clap" + }, + .libxau = .{ + .path = "./external/libxau.zig/" }, }, } diff --git a/external/libxau.zig b/external/libxau.zig new file mode 160000 index 0000000..2ae0979 --- /dev/null +++ b/external/libxau.zig @@ -0,0 +1 @@ +Subproject commit 2ae09794b888e8a40e78bab24b2457fe98030eb0 diff --git a/external/zig-clap b/external/zig-clap new file mode 160000 index 0000000..5289e07 --- /dev/null +++ b/external/zig-clap @@ -0,0 +1 @@ +Subproject commit 5289e0753cd274d65344bef1c114284c633536ea diff --git a/lib/xcb/protocol.zig b/lib/xcb/protocol.zig index 73cac09..fe66a6a 100644 --- a/lib/xcb/protocol.zig +++ b/lib/xcb/protocol.zig @@ -15,7 +15,7 @@ pub const Enum = @import("protocol/enum.zig"); pub const Error = @import("protocol/error.zig"); pub const Event = @import("protocol/event.zig"); pub const EventStruct = @import("protocol/eventstruct.zig"); -pub usingnamespace @import("protocol/field.zig"); +pub const Field = @import("protocol/field.zig"); pub const Request = @import("protocol/request.zig"); pub const Struct = @import("protocol/struct.zig"); pub const Union = @import("protocol/union.zig"); From 0434edaa2815dc4fbb32511d614f2a2055bcf6a1 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Tue, 2 Sep 2025 15:24:51 -0400 Subject: [PATCH 02/12] chore: update build.zig and libxau.zig --- build.zig | 109 ++++++++++++++++++++++++++++++++------------ external/libxau.zig | 2 +- 2 files changed, 82 insertions(+), 29 deletions(-) diff --git a/build.zig b/build.zig index 6b3acd6..a8aa125 100644 --- a/build.zig +++ b/build.zig @@ -6,61 +6,114 @@ pub const Protocol = @import("lib/xcb/protocol.zig"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const no_docs = b.option(bool, "no-docs", "skip installing documentation") orelse false; - const linkage: std.builtin.LinkMode = - b.option(std.builtin.LinkMode, "linkage", "whether to statically or dynamically link the library") orelse - if (target.result.isGnuLibC()) - .dynamic - else - .static; - - const clap = b.dependency("clap", .{ - .target = target, - .optimize = optimize, - }); + // const no_docs = b.option(bool, "no-docs", "skip installing documentation") orelse false; + // const linkage: std.builtin.LinkMode = + // b.option(std.builtin.LinkMode, "linkage", "whether to statically or dynamically link the library") orelse + // if (target.result.isGnuLibC()) + // .dynamic + // else + // .static; + + // const clap = b.dependency("clap", .{ + // .target = target, + // .optimize = optimize, + // }); const libxcb_upstream = b.dependency("libxcb", .{}); const xcbproto_upstream = b.dependency("xcbproto", .{}); - const libxau = b.dependency("libxau", .{ - .target = target, - .optimize = optimize, - .linkage = linkage, - }); + // const libxau = b.dependency("libxau", .{ + // .target = target, + // .optimize = optimize, + // .linkage = linkage, + // }); - const libxau_upstream = libxau.builder.dependency("libxau", .{}); - const xorgproto_upstream = libxau.builder.dependency("xorgproto", .{}); + // const xorgproto_upstream = libxau.builder.dependency("xorgproto", .{}); - const xcb_util_upstream = b.dependency("xcb-util", .{}); - const xcb_util_image_upstream = b.dependency("xcb-util-image", .{}); + // const xcb_util_upstream = b.dependency("xcb-util", .{}); + // const xcb_util_image_upstream = b.dependency("xcb-util-image", .{}); const python3_path = try b.findProgram(&.{ "python3", "python" }, &.{}); - var xproto_c_sources = try std.ArrayList(Build.LazyPath).initCapacity(b.allocator, 0); + var xproto_c_sources_base: Build.LazyPath = undefined; + var xproto_c_sources = try std.ArrayList([]const u8).initCapacity(b.allocator, 0); const libxcb_mod = b.createModule(.{ .target = target, .optimize = optimize, }); const libxcb = b.addLibrary(.{ - .name = "libxcb", + .name = "xcb", .root_module = libxcb_mod, }); - const xcb_proto_path = blk: { + libxcb.linkLibC(); + + { + const libxcb_src = libxcb_upstream.path("src"); + const libxcb_c_client = libxcb_upstream.path("src/c_client.py"); + + xproto_c_sources_base = libxcb_src; + for (xml_files) |xml_file| { + const c_file = b.fmt("{s}.c", .{xml_file[0 .. xml_file.len - 4]}); + const cmd = b.addSystemCommand(&.{python3_path}); - cmd.addFileArg(libxcb_upstream.path("src/c_client.py")); + cmd.addFileArg(libxcb_c_client); cmd.addArgs(&.{ "-c", "libxcb", "-l", "libxcb", "-s", "3", "-p" }); - cmd.addDirectoryArg(xcbproto_upstream.path(".")); - cmd.addFileArg(xcbproto_upstream.path(".")); + cmd.addDirectoryArg(xcbproto_upstream.path("")); cmd.addFileArg(xcbproto_upstream.path(b.fmt("src/{s}", .{xml_file}))); + + cmd.setCwd(libxcb_src); + + const xproto_c_file_path = cwdOutFile(b, cmd, c_file); + + // libxcb.step.dependOn(&cmd.step); + + libxcb.addCSourceFile(.{ + .file = xproto_c_file_path, + .flags = &.{ + "-DXCB_QUEUE_BUFFER_SIZE=16384", + "-DIOV_MAX=16", + }, + }); + + try xproto_c_sources.append(b.allocator, c_file); } + } + + libxcb.addCSourceFiles(.{ + .files = xproto_c_sources.items, + .root = xproto_c_sources_base, + .flags = &.{ + "-DXCB_QUEUE_BUFFER_SIZE=16384", + "-DIOV_MAX=16", + }, + }); + + libxcb.installHeadersDirectory( + xproto_c_sources_base, + "", + .{}, + ); + + b.installArtifact(libxcb); +} + +fn cwdOutFile(b: *Build, run: *Build.Step.Run, path: []const u8) Build.LazyPath { + const cwd = run.cwd.?; + const abs_path = cwd.join(b.allocator, path) catch @panic("OOM"); + const gen_file = b.allocator.create( Build.GeneratedFile ) catch @panic("OOM"); + gen_file.* = .{ .step = &run.step, .path = abs_path.getPath(b) }; + return .{ + .generated = .{ + .file = gen_file, + }, }; } const xml_files = [_][]const u8{ - "xcb.xsd", + // "xcb.xsd", "xproto.xml", "bigreq.xml", "composite.xml", diff --git a/external/libxau.zig b/external/libxau.zig index 2ae0979..d8823d3 160000 --- a/external/libxau.zig +++ b/external/libxau.zig @@ -1 +1 @@ -Subproject commit 2ae09794b888e8a40e78bab24b2457fe98030eb0 +Subproject commit d8823d37dc974d06086dbb02dc01ed07ba9bfa62 From 5efaee3e1ce55c21aaba3ffe5a0bc06fe5117535 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Wed, 3 Sep 2025 01:37:44 -0400 Subject: [PATCH 03/12] chore: minimize python calls --- build.zig | 142 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 47 deletions(-) diff --git a/build.zig b/build.zig index a8aa125..8a8636c 100644 --- a/build.zig +++ b/build.zig @@ -7,12 +7,12 @@ pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); // const no_docs = b.option(bool, "no-docs", "skip installing documentation") orelse false; - // const linkage: std.builtin.LinkMode = - // b.option(std.builtin.LinkMode, "linkage", "whether to statically or dynamically link the library") orelse - // if (target.result.isGnuLibC()) - // .dynamic - // else - // .static; + const linkage: std.builtin.LinkMode = + b.option(std.builtin.LinkMode, "linkage", "whether to statically or dynamically link the library") orelse + if (target.result.isGnuLibC()) + .dynamic + else + .static; // const clap = b.dependency("clap", .{ // .target = target, @@ -22,22 +22,19 @@ pub fn build(b: *std.Build) !void { const libxcb_upstream = b.dependency("libxcb", .{}); const xcbproto_upstream = b.dependency("xcbproto", .{}); - // const libxau = b.dependency("libxau", .{ - // .target = target, - // .optimize = optimize, - // .linkage = linkage, - // }); + const libxau = b.dependency("libxau", .{ + .target = target, + .optimize = optimize, + .linkage = linkage, + }); - // const xorgproto_upstream = libxau.builder.dependency("xorgproto", .{}); + const xorgproto_upstream = libxau.builder.dependency("xorgproto", .{}); - // const xcb_util_upstream = b.dependency("xcb-util", .{}); - // const xcb_util_image_upstream = b.dependency("xcb-util-image", .{}); + const xcb_util_upstream = b.dependency("xcb-util", .{}); + const xcb_util_image_upstream = b.dependency("xcb-util-image", .{}); const python3_path = try b.findProgram(&.{ "python3", "python" }, &.{}); - var xproto_c_sources_base: Build.LazyPath = undefined; - var xproto_c_sources = try std.ArrayList([]const u8).initCapacity(b.allocator, 0); - const libxcb_mod = b.createModule(.{ .target = target, .optimize = optimize, @@ -49,67 +46,118 @@ pub fn build(b: *std.Build) !void { libxcb.linkLibC(); + const headers = b.addWriteFiles(); + { - const libxcb_src = libxcb_upstream.path("src"); - const libxcb_c_client = libxcb_upstream.path("src/c_client.py"); + const c_client_py = libxcb_upstream.path("src/c_client.py"); + + for (xml_files) |xml_file_basename| { + const c_file_basename = b.fmt("{s}.c", .{xml_file_basename[0 .. xml_file_basename.len - 4]}); + const h_file_basename = b.fmt("{s}.h", .{xml_file_basename[0 .. xml_file_basename.len - 4]}); + + const src_xml_file = b.fmt("src/{s}", .{xml_file_basename}); - xproto_c_sources_base = libxcb_src; + const py = b.addSystemCommand(&.{python3_path}); + py.addFileArg(c_client_py); - for (xml_files) |xml_file| { - const c_file = b.fmt("{s}.c", .{xml_file[0 .. xml_file.len - 4]}); + py.addArgs(&.{ "-c", "libxcb", "-l", "libxcb", "-s", "3", "-p" }); + py.addDirectoryArg(xcbproto_upstream.path("")); + py.addFileArg(xcbproto_upstream.path(src_xml_file)); - const cmd = b.addSystemCommand(&.{python3_path}); - cmd.addFileArg(libxcb_c_client); - cmd.addArgs(&.{ "-c", "libxcb", "-l", "libxcb", "-s", "3", "-p" }); - cmd.addDirectoryArg(xcbproto_upstream.path("")); - cmd.addFileArg(xcbproto_upstream.path(b.fmt("src/{s}", .{xml_file}))); + py.setCwd(libxcb_upstream.path("src")); - cmd.setCwd(libxcb_src); + // not the greatest but works + const cat_c = b.addSystemCommand(&.{"cat"}); + cat_c.setCwd(py.cwd.?); + cat_c.addArg(c_file_basename); - const xproto_c_file_path = cwdOutFile(b, cmd, c_file); + const c_file = cat_c.captureStdOut(); + cat_c.captured_stdout.?.basename = c_file_basename; - // libxcb.step.dependOn(&cmd.step); + const cat_h = b.addSystemCommand(&.{"cat"}); + cat_h.setCwd(py.cwd.?); + cat_h.addArg(h_file_basename); + + const h_file = cat_h.captureStdOut(); + cat_h.captured_stdout.?.basename = h_file_basename; libxcb.addCSourceFile(.{ - .file = xproto_c_file_path, + .file = c_file, .flags = &.{ "-DXCB_QUEUE_BUFFER_SIZE=16384", "-DIOV_MAX=16", }, }); - try xproto_c_sources.append(b.allocator, c_file); + _ = headers.addCopyFile( + h_file, + b.fmt("xcb/{s}", .{h_file_basename}), + ); } } + _ = headers.addCopyDirectory( + xorgproto_upstream.path("include"), + "", + .{ .include_extensions = &.{".h"} }, + ); + + _ = headers.addCopyFile(libxcb_upstream.path("src/xcb.h"), "xcb/xcb.h"); + _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_atom.h"), "xcb/xcb_atom.h"); + _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_aux.h"), "xcb/xcb_aux.h"); + _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_event.h"), "xcb/xcb_event.h"); + _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_util.h"), "xcb/xcb_util.h"); + _ = headers.addCopyFile(xcb_util_image_upstream.path("image/xcb_bitops.h"), "xcb/xcb_bitops.h"); + _ = headers.addCopyFile(xcb_util_image_upstream.path("image/xcb_image.h"), "xcb/xcb_image.h"); + _ = headers.addCopyFile(xcb_util_image_upstream.path("image/xcb_pixel.h"), "xcb/xcb_pixel.h"); + libxcb.addCSourceFiles(.{ - .files = xproto_c_sources.items, - .root = xproto_c_sources_base, + .root = libxcb_upstream.path("."), + .files = &.{ + "src/xcb_auth.c", + "src/xcb_conn.c", + "src/xcb_ext.c", + "src/xcb_in.c", + "src/xcb_list.c", + "src/xcb_out.c", + "src/xcb_util.c", + "src/xcb_xid.c", + }, .flags = &.{ "-DXCB_QUEUE_BUFFER_SIZE=16384", "-DIOV_MAX=16", }, }); - libxcb.installHeadersDirectory( - xproto_c_sources_base, - "", - .{}, - ); + libxcb.addIncludePath(libxcb_upstream.path("src")); + libxcb.addIncludePath(libxcb_upstream.path("include")); + libxcb.addIncludePath(xorgproto_upstream.path("include")); + libxcb.addIncludePath(headers.getDirectory().path(b, "include")); + + libxcb.linkLibrary(libxau.artifact("Xau")); + + libxcb.installHeadersDirectory(headers.getDirectory(), "", .{}); + libxcb.addIncludePath(headers.getDirectory()); b.installArtifact(libxcb); } -fn cwdOutFile(b: *Build, run: *Build.Step.Run, path: []const u8) Build.LazyPath { +fn cwdOutFile(b: *Build, run: *Build.Step.Run, basename: []const u8) Build.LazyPath { const cwd = run.cwd.?; - const abs_path = cwd.join(b.allocator, path) catch @panic("OOM"); - const gen_file = b.allocator.create( Build.GeneratedFile ) catch @panic("OOM"); - gen_file.* = .{ .step = &run.step, .path = abs_path.getPath(b) }; - return .{ - .generated = .{ - .file = gen_file, - }, + const abs_path = cwd.join(b.allocator, basename) catch @panic("OOM"); + const output = b.allocator.create(Build.Step.Run.Output) catch @panic("OOM"); + + output.* = .{ + .prefix = "", + .basename = basename, + .generated_file = .{ .step = &run.step, .path = abs_path.getPath(b) }, }; + + if (run.rename_step_with_output_arg) { + run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename })); + } + + return .{ .generated = .{ .file = &output.generated_file } }; } const xml_files = [_][]const u8{ From 20a11d8853edb45e0681afd86c337256309f6304 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Wed, 3 Sep 2025 05:19:49 -0400 Subject: [PATCH 04/12] build: xcb-shm, xcb-util, xcb-image --- build.zig | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/build.zig b/build.zig index 8a8636c..3a53268 100644 --- a/build.zig +++ b/build.zig @@ -35,13 +35,13 @@ pub fn build(b: *std.Build) !void { const python3_path = try b.findProgram(&.{ "python3", "python" }, &.{}); - const libxcb_mod = b.createModule(.{ - .target = target, - .optimize = optimize, - }); const libxcb = b.addLibrary(.{ .name = "xcb", - .root_module = libxcb_mod, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + }), + .linkage = linkage, }); libxcb.linkLibC(); @@ -66,7 +66,7 @@ pub fn build(b: *std.Build) !void { py.setCwd(libxcb_upstream.path("src")); - // not the greatest but works + // not the best but works const cat_c = b.addSystemCommand(&.{"cat"}); cat_c.setCwd(py.cwd.?); cat_c.addArg(c_file_basename); @@ -140,6 +140,73 @@ pub fn build(b: *std.Build) !void { libxcb.addIncludePath(headers.getDirectory()); b.installArtifact(libxcb); + + const libxcb_shm = b.addLibrary(.{ + .name = "xcb-shm", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + .linkage = linkage, + }); + + libxcb_shm.addIncludePath(libxcb_upstream.path("src")); + libxcb_shm.addIncludePath(libxcb_upstream.path("include")); + libxcb_shm.addIncludePath(xorgproto_upstream.path("include")); + libxcb_shm.addIncludePath(headers.getDirectory()); + + libxcb_shm.addCSourceFiles(.{ + .root = libxcb_upstream.path("src"), + .files = &.{ "shm.c", "xinerama.c" }, + }); + + libxcb_shm.linkLibrary(libxcb); + b.installArtifact(libxcb_shm); + + const xcb_util = b.addLibrary(.{ + .name = "xcb-util", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + .linkage = linkage, + }); + + xcb_util.addIncludePath(headers.getDirectory()); + xcb_util.addCSourceFiles(.{ + .root = xcb_util_upstream.path("src"), + .files = &.{ + "atoms.c", + "event.c", + "xcb_aux.c", + }, + }); + + b.installArtifact(xcb_util); + + const xcb_image = b.addLibrary(.{ + .name = "xcb-image", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + .linkage = linkage, + }); + + xcb_image.addIncludePath(headers.getDirectory()); + xcb_image.addCSourceFiles(.{ + .root = xcb_util_image_upstream.path("image"), + .files = &.{ + "xcb_image.c", + }, + }); + + xcb_image.linkLibrary(xcb_util); + xcb_image.linkLibrary(libxcb_shm); + b.installArtifact(xcb_image); } fn cwdOutFile(b: *Build, run: *Build.Step.Run, basename: []const u8) Build.LazyPath { From 55853f241e8fa9bc8c05f8795ff3f4880b250d08 Mon Sep 17 00:00:00 2001 From: PaNDa2Code Date: Thu, 4 Sep 2025 06:08:50 +0300 Subject: [PATCH 05/12] build: update build.zig.zon and libxau.zig --- build.zig | 2 ++ build.zig.zon | 23 +++++++++++++---------- external/libxau.zig | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/build.zig b/build.zig index 3a53268..8b5c08c 100644 --- a/build.zig +++ b/build.zig @@ -71,6 +71,8 @@ pub fn build(b: *std.Build) !void { cat_c.setCwd(py.cwd.?); cat_c.addArg(c_file_basename); + cat_c.step.dependOn(&py.step); + const c_file = cat_c.captureStdOut(); cat_c.captured_stdout.?.basename = c_file_basename; diff --git a/build.zig.zon b/build.zig.zon index 7aac606..6359fa8 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,30 +2,33 @@ .name = .xcb, .fingerprint = 0x48cfd8eae06c78ea, .version = "0.1.16", + .minimum_zig_version = "0.14.0", .paths = .{""}, .dependencies = .{ + .clap = .{ .path = "./external/zig-clap" }, + .libxau = .{ + .path = "./external/libxau.zig", + }, + .libxcb = .{ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb/-/archive/libxcb-1.16/libxcb-libxcb-1.16.tar.gz", - .hash = "1220c6c1f5516d0fe1ca72f5391f7f00f3114c0761cedeccbeeb5d8e7efaefc87fbc", + .hash = "N-V-__8AAKlsCQDGwfVRbQ_hynL1OR9_APMRTAdhzt7Mvutd", }, .xcbproto = .{ .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.16.0/xcbproto-xcb-proto-1.16.0.tar.gz", - .hash = "122088858bfa13f990603440f3b13aa027abfa828de875497fcb58efd017fe0af6ea", + .hash = "N-V-__8AAAPHDACIhYv6E_mQYDRA87E6oCer-oKN6HVJf8tY", }, .@"xcb-util" = .{ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb-util/-/archive/xcb-util-0.4.1/libxcb-util-xcb-util-0.4.1.tar.gz", - .hash = "1220096cb9b583a14b307609801d8a018a3babc9e608170afc521a0db4e437165c15", + .hash = "N-V-__8AAMqcAAAJbLm1g6FLMHYJgB2KAYo7q8nmCBcK_FIa", }, .@"xcb-util-image" = .{ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb-image/-/archive/xcb-util-image-0.4.1/libxcb-image-xcb-util-image-0.4.1.tar.gz", - .hash = "122092beed2990a3b55f6ad7984159e2e53ef2372ecd36d95deeda007ee3903a6797", + .hash = "N-V-__8AAIogAgCSvu0pkKO1X2rXmEFZ4uU-8jcuzTbZXe7a", }, - - .clap = .{ - .path = "./external/zig-clap" - }, - .libxau = .{ - .path = "./external/libxau.zig/" + .xproto = .{ + .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.16.0/xcbproto-xcb-proto-1.16.0.tar.gz", + .hash = "N-V-__8AAAPHDACIhYv6E_mQYDRA87E6oCer-oKN6HVJf8tY", }, }, } diff --git a/external/libxau.zig b/external/libxau.zig index d8823d3..ecf4795 160000 --- a/external/libxau.zig +++ b/external/libxau.zig @@ -1 +1 @@ -Subproject commit d8823d37dc974d06086dbb02dc01ed07ba9bfa62 +Subproject commit ecf47950d762b7843cd824b751e1d1523dd65dc5 From f5c52cac934b5346b2779fdcf9c9de9ead2ac84b Mon Sep 17 00:00:00 2001 From: PaNDa2Code Date: Thu, 4 Sep 2025 15:04:58 +0300 Subject: [PATCH 06/12] fix: libxcb missing header --- build.zig | 84 +++++++++++++++++++++------------------------ build.zig.zon | 4 ++- external/libxau.zig | 2 +- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/build.zig b/build.zig index 8b5c08c..887f50e 100644 --- a/build.zig +++ b/build.zig @@ -50,6 +50,7 @@ pub fn build(b: *std.Build) !void { { const c_client_py = libxcb_upstream.path("src/c_client.py"); + const sources = b.addWriteFiles(); for (xml_files) |xml_file_basename| { const c_file_basename = b.fmt("{s}.c", .{xml_file_basename[0 .. xml_file_basename.len - 4]}); @@ -67,35 +68,30 @@ pub fn build(b: *std.Build) !void { py.setCwd(libxcb_upstream.path("src")); // not the best but works - const cat_c = b.addSystemCommand(&.{"cat"}); - cat_c.setCwd(py.cwd.?); - cat_c.addArg(c_file_basename); - - cat_c.step.dependOn(&py.step); - - const c_file = cat_c.captureStdOut(); - cat_c.captured_stdout.?.basename = c_file_basename; - - const cat_h = b.addSystemCommand(&.{"cat"}); - cat_h.setCwd(py.cwd.?); - cat_h.addArg(h_file_basename); - - const h_file = cat_h.captureStdOut(); - cat_h.captured_stdout.?.basename = h_file_basename; - - libxcb.addCSourceFile(.{ - .file = c_file, - .flags = &.{ - "-DXCB_QUEUE_BUFFER_SIZE=16384", - "-DIOV_MAX=16", - }, - }); + const c_file = cwdOutFile(b, py, c_file_basename); + const h_file = cwdOutFile(b, py, h_file_basename); _ = headers.addCopyFile( h_file, b.fmt("xcb/{s}", .{h_file_basename}), ); + + _ = sources.addCopyFile(c_file, c_file_basename); } + + libxcb.root_module.addCSourceFiles(.{ + .root = sources.getDirectory(), + .files = blk: { + const files_names = try b.allocator.alloc([]const u8, sources.files.items.len); + for (0..files_names.len) |i| + files_names[i] = sources.files.items[i].sub_path; + break :blk files_names; + }, + .flags = &.{ + "-DXCB_QUEUE_BUFFER_SIZE=16384", + "-DIOV_MAX=16", + }, + }); } _ = headers.addCopyDirectory( @@ -131,17 +127,15 @@ pub fn build(b: *std.Build) !void { }, }); - libxcb.addIncludePath(libxcb_upstream.path("src")); - libxcb.addIncludePath(libxcb_upstream.path("include")); - libxcb.addIncludePath(xorgproto_upstream.path("include")); - libxcb.addIncludePath(headers.getDirectory().path(b, "include")); + libxcb.root_module.addIncludePath(libxcb_upstream.path("src")); + libxcb.root_module.addIncludePath(libxcb_upstream.path("include")); + libxcb.root_module.addIncludePath(xorgproto_upstream.path("include")); + libxcb.root_module.addIncludePath(headers.getDirectory().path(b, "include")); - libxcb.linkLibrary(libxau.artifact("Xau")); + libxcb.root_module.linkLibrary(libxau.artifact("Xau")); libxcb.installHeadersDirectory(headers.getDirectory(), "", .{}); - libxcb.addIncludePath(headers.getDirectory()); - - b.installArtifact(libxcb); + libxcb.root_module.addIncludePath(headers.getDirectory()); const libxcb_shm = b.addLibrary(.{ .name = "xcb-shm", @@ -153,19 +147,17 @@ pub fn build(b: *std.Build) !void { .linkage = linkage, }); - libxcb_shm.addIncludePath(libxcb_upstream.path("src")); - libxcb_shm.addIncludePath(libxcb_upstream.path("include")); - libxcb_shm.addIncludePath(xorgproto_upstream.path("include")); - libxcb_shm.addIncludePath(headers.getDirectory()); + libxcb_shm.root_module.addIncludePath(libxcb_upstream.path("src")); + libxcb_shm.root_module.addIncludePath(xorgproto_upstream.path("include")); + libxcb_shm.root_module.addIncludePath(headers.getDirectory()); + + libxcb_shm.root_module.linkLibrary(libxau.artifact("Xau")); libxcb_shm.addCSourceFiles(.{ .root = libxcb_upstream.path("src"), .files = &.{ "shm.c", "xinerama.c" }, }); - libxcb_shm.linkLibrary(libxcb); - b.installArtifact(libxcb_shm); - const xcb_util = b.addLibrary(.{ .name = "xcb-util", .root_module = b.createModule(.{ @@ -176,7 +168,7 @@ pub fn build(b: *std.Build) !void { .linkage = linkage, }); - xcb_util.addIncludePath(headers.getDirectory()); + xcb_util.root_module.addIncludePath(headers.getDirectory()); xcb_util.addCSourceFiles(.{ .root = xcb_util_upstream.path("src"), .files = &.{ @@ -186,8 +178,6 @@ pub fn build(b: *std.Build) !void { }, }); - b.installArtifact(xcb_util); - const xcb_image = b.addLibrary(.{ .name = "xcb-image", .root_module = b.createModule(.{ @@ -198,7 +188,7 @@ pub fn build(b: *std.Build) !void { .linkage = linkage, }); - xcb_image.addIncludePath(headers.getDirectory()); + xcb_image.root_module.addIncludePath(headers.getDirectory()); xcb_image.addCSourceFiles(.{ .root = xcb_util_image_upstream.path("image"), .files = &.{ @@ -206,9 +196,13 @@ pub fn build(b: *std.Build) !void { }, }); - xcb_image.linkLibrary(xcb_util); - xcb_image.linkLibrary(libxcb_shm); - b.installArtifact(xcb_image); + xcb_image.root_module.linkLibrary(xcb_util); + xcb_image.root_module.linkLibrary(libxcb_shm); + + libxcb.installHeadersDirectory(headers.getDirectory(), "", .{}); + libxcb.root_module.linkLibrary(xcb_image); + + b.installArtifact(libxcb); } fn cwdOutFile(b: *Build, run: *Build.Step.Run, basename: []const u8) Build.LazyPath { diff --git a/build.zig.zon b/build.zig.zon index 6359fa8..b6045af 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,7 +5,9 @@ .minimum_zig_version = "0.14.0", .paths = .{""}, .dependencies = .{ - .clap = .{ .path = "./external/zig-clap" }, + .clap = .{ + .path = "./external/zig-clap", + }, .libxau = .{ .path = "./external/libxau.zig", }, diff --git a/external/libxau.zig b/external/libxau.zig index ecf4795..0e129be 160000 --- a/external/libxau.zig +++ b/external/libxau.zig @@ -1 +1 @@ -Subproject commit ecf47950d762b7843cd824b751e1d1523dd65dc5 +Subproject commit 0e129be42205a99d329b3737476a0dc828857779 From ac4fa73fbc63551b2c7c627dae3226b5d8ad6775 Mon Sep 17 00:00:00 2001 From: PaNDa2Code Date: Thu, 4 Sep 2025 15:15:45 +0300 Subject: [PATCH 07/12] build: use urls --- build.zig.zon | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index b6045af..496deb1 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,13 +5,6 @@ .minimum_zig_version = "0.14.0", .paths = .{""}, .dependencies = .{ - .clap = .{ - .path = "./external/zig-clap", - }, - .libxau = .{ - .path = "./external/libxau.zig", - }, - .libxcb = .{ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb/-/archive/libxcb-1.16/libxcb-libxcb-1.16.tar.gz", .hash = "N-V-__8AAKlsCQDGwfVRbQ_hynL1OR9_APMRTAdhzt7Mvutd", @@ -32,5 +25,13 @@ .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.16.0/xcbproto-xcb-proto-1.16.0.tar.gz", .hash = "N-V-__8AAAPHDACIhYv6E_mQYDRA87E6oCer-oKN6HVJf8tY", }, + .clap = .{ + .url = "https://github.com/Hejsil/zig-clap/archive/refs/tags/0.11.0.tar.gz", + .hash = "clap-0.11.0-oBajB-HnAQDPCKYzwF7rO3qDFwRcD39Q0DALlTSz5H7e", + }, + .libxau = .{ + .url = "https://github.com/PaNDa2code/libxau_zig/archive/0e129be42205a99d329b3737476a0dc828857779.tar.gz", + .hash = "libxau-1.0.11-kZh3fMiRAAAjO0giWUHQ2CR4jvq-6ThU46cz1eNx7ZnE", + }, }, } From 9e89ed25fb6dc49bb0e743436fc7045b5743f6a9 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Thu, 4 Sep 2025 16:05:21 -0400 Subject: [PATCH 08/12] build: compile and link libXdmcp --- build.zig | 39 ++++++++++++++++++++++++++++++++++++++- build.zig.zon | 4 ++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 887f50e..5ef35fc 100644 --- a/build.zig +++ b/build.zig @@ -32,6 +32,7 @@ pub fn build(b: *std.Build) !void { const xcb_util_upstream = b.dependency("xcb-util", .{}); const xcb_util_image_upstream = b.dependency("xcb-util-image", .{}); + const libxdmcp_upstream = b.dependency("libXdmcp", .{}); const python3_path = try b.findProgram(&.{ "python3", "python" }, &.{}); @@ -47,8 +48,10 @@ pub fn build(b: *std.Build) !void { libxcb.linkLibC(); const headers = b.addWriteFiles(); - { + const xcbgen = xcbproto_upstream.path("xcbgen"); + const xcbgen_path = xcbgen.getPath3(b, null).root_dir.path.?; + const c_client_py = libxcb_upstream.path("src/c_client.py"); const sources = b.addWriteFiles(); @@ -60,6 +63,7 @@ pub fn build(b: *std.Build) !void { const py = b.addSystemCommand(&.{python3_path}); py.addFileArg(c_client_py); + py.setEnvironmentVariable("PYTHONPATH", xcbgen_path); py.addArgs(&.{ "-c", "libxcb", "-l", "libxcb", "-s", "3", "-p" }); py.addDirectoryArg(xcbproto_upstream.path("")); @@ -202,6 +206,39 @@ pub fn build(b: *std.Build) !void { libxcb.installHeadersDirectory(headers.getDirectory(), "", .{}); libxcb.root_module.linkLibrary(xcb_image); + const libxdmcp = b.addLibrary(.{ + .name = "Xdmcp", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + .linkage = linkage, + }); + + libxdmcp.root_module.addCSourceFiles(.{ + .root = libxdmcp_upstream.path(""), + .files = &.{ + "Array.c", + "Fill.c", + "Flush.c", + "Key.c", + "Read.c", + "Unwrap.c", + "Wrap.c", + "Write.c", + }, + .flags = &.{ + "-DHAVE_ARC4RANDOM_BUF", + }, + }); + + libxdmcp.root_module.addIncludePath(xorgproto_upstream.path("include")); + libxdmcp.root_module.addIncludePath(libxdmcp_upstream.path("include")); + libxdmcp.root_module.addIncludePath(headers.getDirectory()); + + libxcb.root_module.linkLibrary(libxdmcp); + b.installArtifact(libxcb); } diff --git a/build.zig.zon b/build.zig.zon index 496deb1..5ce772b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -33,5 +33,9 @@ .url = "https://github.com/PaNDa2code/libxau_zig/archive/0e129be42205a99d329b3737476a0dc828857779.tar.gz", .hash = "libxau-1.0.11-kZh3fMiRAAAjO0giWUHQ2CR4jvq-6ThU46cz1eNx7ZnE", }, + .libXdmcp = .{ + .url = "https://gitlab.freedesktop.org/xorg/lib/libxdmcp/-/archive/libXdmcp-1.1.5/libxdmcp-libXdmcp-1.1.5.tar.gz", + .hash = "N-V-__8AAHC7AgA7EvtCRM2pOGbGmSYsVrYJoTPjVbUX1_ue", + }, }, } From c6752841934a07ec7879b99f0577d1103ad0f9c7 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Thu, 4 Sep 2025 19:18:38 -0400 Subject: [PATCH 09/12] build: fix arc4random_buf undefinedin static builds --- build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 5ef35fc..b4ba014 100644 --- a/build.zig +++ b/build.zig @@ -229,7 +229,7 @@ pub fn build(b: *std.Build) !void { "Write.c", }, .flags = &.{ - "-DHAVE_ARC4RANDOM_BUF", + if (linkage == .dynamic) "-DHAVE_ARC4RANDOM_BUF" else "", }, }); From b129f5ce95b998a02b1b2c655064d317d10b1a68 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Thu, 4 Sep 2025 22:55:20 -0400 Subject: [PATCH 10/12] feat: use libxcb 1.17.0 --- build.zig.zon | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 5ce772b..7f0812c 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,17 +1,17 @@ .{ .name = .xcb, .fingerprint = 0x48cfd8eae06c78ea, - .version = "0.1.16", + .version = "0.1.17", .minimum_zig_version = "0.14.0", .paths = .{""}, .dependencies = .{ .libxcb = .{ - .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb/-/archive/libxcb-1.16/libxcb-libxcb-1.16.tar.gz", - .hash = "N-V-__8AAKlsCQDGwfVRbQ_hynL1OR9_APMRTAdhzt7Mvutd", + .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb/-/archive/libxcb-1.17.0/libxcb-libxcb-1.17.0.tar.gz", + .hash = "N-V-__8AAPZxCQD7JyQLx0_D9J9dnkSoP7iziBVxreTgUqlj", }, .xcbproto = .{ - .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.16.0/xcbproto-xcb-proto-1.16.0.tar.gz", - .hash = "N-V-__8AAAPHDACIhYv6E_mQYDRA87E6oCer-oKN6HVJf8tY", + .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.17.0/xcbproto-xcb-proto-1.17.0.tar.gz", + .hash = "N-V-__8AAFnMDACdXT5YIakLgEMFZ-K7ZICgB18p8xKobHjk", }, .@"xcb-util" = .{ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb-util/-/archive/xcb-util-0.4.1/libxcb-util-xcb-util-0.4.1.tar.gz", @@ -21,10 +21,6 @@ .url = "https://gitlab.freedesktop.org/xorg/lib/libxcb-image/-/archive/xcb-util-image-0.4.1/libxcb-image-xcb-util-image-0.4.1.tar.gz", .hash = "N-V-__8AAIogAgCSvu0pkKO1X2rXmEFZ4uU-8jcuzTbZXe7a", }, - .xproto = .{ - .url = "https://gitlab.freedesktop.org/xorg/proto/xcbproto/-/archive/xcb-proto-1.16.0/xcbproto-xcb-proto-1.16.0.tar.gz", - .hash = "N-V-__8AAAPHDACIhYv6E_mQYDRA87E6oCer-oKN6HVJf8tY", - }, .clap = .{ .url = "https://github.com/Hejsil/zig-clap/archive/refs/tags/0.11.0.tar.gz", .hash = "clap-0.11.0-oBajB-HnAQDPCKYzwF7rO3qDFwRcD39Q0DALlTSz5H7e", From b38f8534ac3112961e57dba53c97781eddf42832 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Fri, 5 Sep 2025 00:45:49 -0400 Subject: [PATCH 11/12] feat: add python wrapper script for cache --- build.zig | 38 +++++++++++++++---------- script/c_client.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 script/c_client.py diff --git a/build.zig b/build.zig index b4ba014..22927ed 100644 --- a/build.zig +++ b/build.zig @@ -48,22 +48,32 @@ pub fn build(b: *std.Build) !void { libxcb.linkLibC(); const headers = b.addWriteFiles(); + const c_client_sources = b.addWriteFiles(); { const xcbgen = xcbproto_upstream.path("xcbgen"); const xcbgen_path = xcbgen.getPath3(b, null).root_dir.path.?; const c_client_py = libxcb_upstream.path("src/c_client.py"); - const sources = b.addWriteFiles(); + const c_client_py_wrapper = b.path("script/c_client.py"); for (xml_files) |xml_file_basename| { const c_file_basename = b.fmt("{s}.c", .{xml_file_basename[0 .. xml_file_basename.len - 4]}); const h_file_basename = b.fmt("{s}.h", .{xml_file_basename[0 .. xml_file_basename.len - 4]}); + const PYTHONPATH = b.fmt("{s}:{s}", .{ + c_client_py.dirname().getPath3(b, null).root_dir.path.?, + xcbgen_path, + }); const src_xml_file = b.fmt("src/{s}", .{xml_file_basename}); const py = b.addSystemCommand(&.{python3_path}); - py.addFileArg(c_client_py); - py.setEnvironmentVariable("PYTHONPATH", xcbgen_path); + py.setEnvironmentVariable("PYTHONPATH", PYTHONPATH); + py.addFileArg(c_client_py_wrapper); + py.addPrefixedFileArg("--child-script=", c_client_py); + + // not the best but works + const c_file = py.addPrefixedOutputFileArg("--c-output=", c_file_basename); + const h_file = py.addPrefixedOutputFileArg("--h-output=", h_file_basename); py.addArgs(&.{ "-c", "libxcb", "-l", "libxcb", "-s", "3", "-p" }); py.addDirectoryArg(xcbproto_upstream.path("")); @@ -71,24 +81,20 @@ pub fn build(b: *std.Build) !void { py.setCwd(libxcb_upstream.path("src")); - // not the best but works - const c_file = cwdOutFile(b, py, c_file_basename); - const h_file = cwdOutFile(b, py, h_file_basename); - _ = headers.addCopyFile( h_file, b.fmt("xcb/{s}", .{h_file_basename}), ); - _ = sources.addCopyFile(c_file, c_file_basename); + _ = c_client_sources.addCopyFile(c_file, c_file_basename); } libxcb.root_module.addCSourceFiles(.{ - .root = sources.getDirectory(), + .root = c_client_sources.getDirectory(), .files = blk: { - const files_names = try b.allocator.alloc([]const u8, sources.files.items.len); + const files_names = try b.allocator.alloc([]const u8, c_client_sources.files.items.len); for (0..files_names.len) |i| - files_names[i] = sources.files.items[i].sub_path; + files_names[i] = c_client_sources.files.items[i].sub_path; break :blk files_names; }, .flags = &.{ @@ -105,6 +111,8 @@ pub fn build(b: *std.Build) !void { ); _ = headers.addCopyFile(libxcb_upstream.path("src/xcb.h"), "xcb/xcb.h"); + _ = headers.addCopyFile(libxcb_upstream.path("src/xcbext.h"), "xcb/xcbext.h"); + _ = headers.addCopyFile(libxcb_upstream.path("src/xcbint.h"), "xcb/xcbint.h"); _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_atom.h"), "xcb/xcb_atom.h"); _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_aux.h"), "xcb/xcb_aux.h"); _ = headers.addCopyFile(xcb_util_upstream.path("src/xcb_event.h"), "xcb/xcb_event.h"); @@ -131,9 +139,8 @@ pub fn build(b: *std.Build) !void { }, }); - libxcb.root_module.addIncludePath(libxcb_upstream.path("src")); - libxcb.root_module.addIncludePath(libxcb_upstream.path("include")); libxcb.root_module.addIncludePath(xorgproto_upstream.path("include")); + libxcb.root_module.addIncludePath(headers.getDirectory().path(b, "xcb")); libxcb.root_module.addIncludePath(headers.getDirectory().path(b, "include")); libxcb.root_module.linkLibrary(libxau.artifact("Xau")); @@ -153,12 +160,12 @@ pub fn build(b: *std.Build) !void { libxcb_shm.root_module.addIncludePath(libxcb_upstream.path("src")); libxcb_shm.root_module.addIncludePath(xorgproto_upstream.path("include")); - libxcb_shm.root_module.addIncludePath(headers.getDirectory()); + libxcb_shm.root_module.addIncludePath(headers.getDirectory().path(b, "xcb")); libxcb_shm.root_module.linkLibrary(libxau.artifact("Xau")); libxcb_shm.addCSourceFiles(.{ - .root = libxcb_upstream.path("src"), + .root = c_client_sources.getDirectory(), .files = &.{ "shm.c", "xinerama.c" }, }); @@ -260,6 +267,7 @@ fn cwdOutFile(b: *Build, run: *Build.Step.Run, basename: []const u8) Build.LazyP return .{ .generated = .{ .file = &output.generated_file } }; } + const xml_files = [_][]const u8{ // "xcb.xsd", "xproto.xml", diff --git a/script/c_client.py b/script/c_client.py new file mode 100644 index 0000000..14b30e2 --- /dev/null +++ b/script/c_client.py @@ -0,0 +1,70 @@ +import sys +import os +import getopt +import subprocess +import shutil + +def main(): + try: + opts, args = getopt.getopt( + sys.argv[1:], + "c:l:s:p:m", + ["server-side", "child-script=", "c-output=", "h-output="] + ) + except getopt.GetoptError as err: + print("Error:", err) + sys.exit(1) + + c_output = None + h_output = None + child_script = None + + # Options to forward to c_client.py + forward_opts = [] + + for (opt, arg) in opts: + if opt == "--child-script": + child_script = arg + elif opt == "--c-output": + c_output = arg + elif opt == "--h-output": + h_output = arg + else: + if arg: + forward_opts.extend([opt, arg]) + else: + forward_opts.append(opt) + + if not c_output: + print("Error: --c-output must be provided") + sys.exit(1) + + if not h_output: + print("Error: --h-output must be provided") + sys.exit(1) + + if not child_script: + print("Error: --child-script must be provided (path to c_client.py)") + sys.exit(1) + + if not args: + print("Error: Missing XML file argument") + sys.exit(1) + + xml_file = args[0] + + # Run child c_client.py with forwarded args + cmd = [sys.executable, child_script] + forward_opts + [xml_file] + subprocess.check_call(cmd) + + # Determine generated base filename (same as XML without extension) + base_name = os.path.splitext(os.path.basename(xml_file))[0] + generated_c = f"{base_name}.c" + generated_h = f"{base_name}.h" + + # Move files if requested + shutil.move(generated_c, c_output) + shutil.move(generated_h, h_output) + +if __name__ == "__main__": + main() From 08716666adb96fb4a5c85b346296a7c9049c1b38 Mon Sep 17 00:00:00 2001 From: PaNDa2code Date: Sun, 14 Sep 2025 11:09:38 -0400 Subject: [PATCH 12/12] build: fix missing arc4random_buf --- build.zig | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 22927ed..73ec43c 100644 --- a/build.zig +++ b/build.zig @@ -235,9 +235,7 @@ pub fn build(b: *std.Build) !void { "Wrap.c", "Write.c", }, - .flags = &.{ - if (linkage == .dynamic) "-DHAVE_ARC4RANDOM_BUF" else "", - }, + .flags = &.{}, }); libxdmcp.root_module.addIncludePath(xorgproto_upstream.path("include")); @@ -267,7 +265,6 @@ fn cwdOutFile(b: *Build, run: *Build.Step.Run, basename: []const u8) Build.LazyP return .{ .generated = .{ .file = &output.generated_file } }; } - const xml_files = [_][]const u8{ // "xcb.xsd", "xproto.xml",