diff --git a/flatpak/dependencies.yml b/flatpak/dependencies.yml index 87512a547..c1a9450e1 100644 --- a/flatpak/dependencies.yml +++ b/flatpak/dependencies.yml @@ -13,12 +13,12 @@ modules: - chmod a+x /app/zig/zig sources: - type: archive - sha256: 02aa270f183da276e5b5920b1dac44a63f1a49e55050ebde3aecc9eb82f93239 - url: https://ziglang.org/download/0.15.2/zig-x86_64-linux-0.15.2.tar.xz + sha256: 70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00 + url: https://ziglang.org/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz only-arches: [x86_64] - type: archive - sha256: 958ed7d1e00d0ea76590d27666efbf7a932281b3d7ba0c6b01b0ff26498f667f - url: https://ziglang.org/download/0.15.2/zig-aarch64-linux-0.15.2.tar.xz + sha256: ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17 + url: https://ziglang.org/download/0.16.0/zig-aarch64-linux-0.16.0.tar.xz only-arches: [aarch64] - name: bzip2-redirect diff --git a/pkg/gtk4-layer-shell/build.zig b/pkg/gtk4-layer-shell/build.zig index 8ab67e62b..38dfd2c8a 100644 --- a/pkg/gtk4-layer-shell/build.zig +++ b/pkg/gtk4-layer-shell/build.zig @@ -39,18 +39,24 @@ pub fn build(b: *std.Build) !void { else link_system_libs_full[0..1], }); + + if (!b.systemIntegrationOption("gtk4-layer-shell", .{})) { + // local deps (non-system layer-shell/wayland) + const deps = try LocalDeps.get(b) orelse break :translate; + headers.addIncludePath(deps.upstream.path("include")); + headers.addIncludePath(deps.upstream.path("src")); + headers.addIncludePath(deps.client_header_directory); + } + module.addImport("c", headers.mod); } if (!b.systemIntegrationOption("gtk4-layer-shell", .{})) { - _ = try buildLib(b, module, .{ - .target = target, - .optimize = optimize, - }); + _ = try buildLib(b, .{ .target = target, .optimize = optimize }); } } -fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Build.Step.Compile { +fn buildLib(b: *std.Build, options: anytype) !*std.Build.Step.Compile { const lib_version = try std.SemanticVersion.parse(version); const target = options.target; const optimize = options.optimize; @@ -67,58 +73,20 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu }); b.installArtifact(lib); - // We need to call both lazy dependencies to tell Zig we need both - const upstream_ = b.lazyDependency("gtk4_layer_shell", .{}); - const wayland_protocols_ = b.lazyDependency("wayland_protocols", .{}); - const upstream = upstream_ orelse return lib; - const wayland_protocols = wayland_protocols_ orelse return lib; - - lib.root_module.addIncludePath(upstream.path("include")); - lib.root_module.addIncludePath(upstream.path("src")); - module.addIncludePath(upstream.path("include")); - // GTK lib.root_module.linkSystemLibrary("gtk4", dynamic_link_opts); - // Wayland headers and source files - { - const protocols = [_]struct { []const u8, std.Build.LazyPath }{ - .{ - "wlr-layer-shell-unstable-v1", - upstream.path("protocol/wlr-layer-shell-unstable-v1.xml"), - }, - .{ - "xdg-shell", - wayland_protocols.path("stable/xdg-shell/xdg-shell.xml"), - }, - // Even though we don't use session lock, we still need its headers - .{ - "ext-session-lock-v1", - wayland_protocols.path("staging/ext-session-lock/ext-session-lock-v1.xml"), - }, - }; - - const wf = b.addWriteFiles(); - for (protocols) |protocol| { - const name, const xml = protocol; - - const header_scanner = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); - header_scanner.addFileArg(xml); - _ = wf.addCopyFile( - header_scanner.addOutputFileArg(name), - b.fmt("{s}-client.h", .{name}), - ); - - const source_scanner = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); - source_scanner.addFileArg(xml); - const source = source_scanner.addOutputFileArg(b.fmt("{s}.c", .{name})); - lib.root_module.addCSourceFile(.{ .file = source }); - } - lib.root_module.addIncludePath(wf.getDirectory()); + // local deps (non-system layer-shell/wayland) + const deps = try LocalDeps.get(b) orelse return lib; + lib.root_module.addIncludePath(deps.upstream.path("include")); + lib.root_module.addIncludePath(deps.upstream.path("src")); + lib.root_module.addIncludePath(deps.client_header_directory); + for (deps.private_code_files) |source| { + lib.root_module.addCSourceFile(.{ .file = source }); } lib.installHeadersDirectory( - upstream.path("include"), + deps.upstream.path("include"), "", .{ .include_extensions = &.{".h"} }, ); @@ -134,7 +102,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu "xdg-surface-server.c", }; lib.root_module.addCSourceFiles(.{ - .root = upstream.path("src"), + .root = deps.upstream.path("src"), .files = srcs, .flags = &.{ b.fmt("-DGTK_LAYER_SHELL_MAJOR={}", .{lib_version.major}), @@ -145,3 +113,68 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu return lib; } + +const LocalDeps = struct { + var cached: ?LocalDeps = null; + + upstream: *std.Build.Dependency, + wayland_protocols: *std.Build.Dependency, + client_header_directory: std.Build.LazyPath, + private_code_files: []std.Build.LazyPath, + + fn init(b: *std.Build) !?LocalDeps { + var result: LocalDeps = .{ + .upstream = b.lazyDependency("gtk4_layer_shell", .{}) orelse return null, + .wayland_protocols = b.lazyDependency("wayland_protocols", .{}) orelse return null, + .client_header_directory = undefined, + .private_code_files = &.{}, + }; + + // Wayland headers and source files + { + const protocols = [_]struct { []const u8, std.Build.LazyPath }{ + .{ + "wlr-layer-shell-unstable-v1", + result.upstream.path("protocol/wlr-layer-shell-unstable-v1.xml"), + }, + .{ + "xdg-shell", + result.wayland_protocols.path("stable/xdg-shell/xdg-shell.xml"), + }, + // Even though we don't use session lock, we still need its headers + .{ + "ext-session-lock-v1", + result.wayland_protocols.path("staging/ext-session-lock/ext-session-lock-v1.xml"), + }, + }; + + const wf = b.addWriteFiles(); + const private_code_files = try b.allocator.alloc(std.Build.LazyPath, protocols.len); + for (protocols, 0..) |protocol, idx| { + const name, const xml = protocol; + + const header_scanner = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); + header_scanner.addFileArg(xml); + _ = wf.addCopyFile( + header_scanner.addOutputFileArg(name), + b.fmt("{s}-client.h", .{name}), + ); + + const source_scanner = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); + source_scanner.addFileArg(xml); + const source = source_scanner.addOutputFileArg(b.fmt("{s}.c", .{name})); + private_code_files[idx] = source; + } + result.private_code_files = private_code_files; + result.client_header_directory = wf.getDirectory(); + } + + cached = result; + return result; + } + + fn get(b: *std.Build) !?LocalDeps { + if (cached) |c| return c; + return init(b); + } +}; diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 7bdbc9b48..1c6ec8bf5 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -52,7 +52,7 @@ parts: rm -rf $CRAFT_PART_SRC/* if [[ -n $arch ]]; then - curl -LO --retry-connrefused --retry 10 https://ziglang.org/download/0.15.2/zig-$arch-linux-0.15.2.tar.xz + curl -LO --retry-connrefused --retry 10 https://ziglang.org/download/0.16.0/zig-$arch-linux-0.16.0.tar.xz else echo "Unsupported arch" exit 1 @@ -61,6 +61,9 @@ parts: tar xf zig-$arch-lin*xz rm -f *xz mv zig-$arch-linux*/* . + + # TODO: remove after IPv6 resolv.conf resolution is fixed in Zig + ln --symbolic --force /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf prime: - -* diff --git a/src/build/Config.zig b/src/build/Config.zig index b412aaa42..5b57dee18 100644 --- a/src/build/Config.zig +++ b/src/build/Config.zig @@ -333,22 +333,39 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf // may be fixed in 0.17.0. We may want to revisit this afterwards; although // I'm not too sure if that helps to clean up rpath, this may just be the // better option. See https://codeberg.org/ziglang/zig/issues/31760. - if ((target.result.os.tag == .linux) and target.query.isNativeCpu()) { - const in_nix_shell = env.get("IN_NIX_SHELL") != null; - if (b.option( - bool, - "patchelf", - "Patch interpreter and rpath in the built binary (default if IN_NIX_SHELL is set)", - ) orelse in_nix_shell) { - var patchelf: PatchElf = .{}; - if (b.findProgram(&.{"ld.so"}, &.{})) |ld_so| { - patchelf.interp = std.Io.Dir.realPathFileAbsoluteAlloc(b.graph.io, ld_so, b.allocator) catch null; - } else |_| {} - if (env.get("LD_LIBRARY_PATH")) |ld_library_path| { - patchelf.rpath = if (ld_library_path.len > 0) ld_library_path else null; - } - if (patchelf.interp != null or patchelf.rpath != null) { - config.patchelf = patchelf; + if (b.option( + []const u8, + "patch-interp", + "Inject the supplied path as the dynamic linker in the built binary. " ++ + "Under Nix, this defaults to the dynamic linker found in PATH.", + )) |interp| { + PatchElf.setInterp(&config, interp); + } else patch_interp: { + if (!(target.result.os.tag == .linux) or !target.query.isNativeCpu()) break :patch_interp; + if (env.get("IN_NIX_SHELL") == null) break :patch_interp; + + if (b.findProgram(&.{"ld.so"}, &.{})) |ld_so| { + PatchElf.setInterp( + &config, + std.Io.Dir.realPathFileAbsoluteAlloc(b.graph.io, ld_so, b.allocator) catch break :patch_interp, + ); + } else |_| {} + } + + if (b.option( + []const u8, + "patch-rpath", + "Inject the supplied colon-delimited search path as the rpath in the built binary. " ++ + "This defaults to LD_LIBRARY_PATH if we're in a Nix shell environment.", + )) |rpath| { + PatchElf.setRpath(&config, rpath); + } else patch_rpath: { + if (!(target.result.os.tag == .linux) or !target.query.isNativeCpu()) break :patch_rpath; + if (env.get("IN_NIX_SHELL") == null) break :patch_rpath; + + if (env.get("LD_LIBRARY_PATH")) |ld_library_path| { + if (ld_library_path.len > 0) { + PatchElf.setRpath(&config, ld_library_path); } } } @@ -543,6 +560,24 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf const PatchElf = struct { interp: ?[]const u8 = null, rpath: ?[]const u8 = null, + + fn setInterp(config: *Config, interp: []const u8) void { + if (config.patchelf) |*patchelf| { + patchelf.interp = interp; + return; + } + + config.patchelf = .{ .interp = interp }; + } + + fn setRpath(config: *Config, rpath: []const u8) void { + if (config.patchelf) |*patchelf| { + patchelf.rpath = rpath; + return; + } + + config.patchelf = .{ .rpath = rpath }; + } }; /// Add a patchelf step for the supplied `artifact`, depending on the supplied