Hi,

as Robert Lillack remarked in his submission of wayland/river:

   The Zig build system currently does not correctly work for linking
   to system libraries in OpenBSD without specifying a version
   number, so a patch for River's build system is necessary.
   https://marc.info/?l=openbsd-ports&m=177944156665691&w=2

There have been prior attempts to make that work on OpenBSD, but it seems
that interest in the feature was lost in early 2024:

   https://github.com/ziglang/zig/pull/18475

Attached is a second attempt. Both as a diff to lang/zig and as a PR on
codeberg: https://codeberg.org/ziglang/zig/pulls/36135

What I can say is that this *works*. I can drop the patch in wayland/river
and it builds and runs fine without.

What I suspect however is that this looks like what it is: A hodgepodge of
Robert's diff and the originally proposed PR that I came up with after reading
a few tutorials.

So if anyone here is a more experienced zig programmer, please review, fix, rewrite or weigh in on the PR :-)

NB: I am looking for feedback from experienced *human* zig programmers (see
zig's no-AI policy).

cheers,
Volker
Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/zig/Makefile,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile
--- Makefile	11 May 2026 21:18:06 -0000	1.32
+++ Makefile	14 Jul 2026 20:02:33 -0000
@@ -7,6 +7,7 @@ COMMENT =	zig compiler and toolchain
 
 V =		0.16.0
 DIST_TUPLE = 	codeberg ziglang zig ${V} .
+REVISION =	0
 
 # see https://codeberg.org/ziglang/zig/src/tag/0.16.0
 ZIG_COMMIT =	24fdd5b7a4c1c8b5deb5b56756b9dbc8e08c86a8
Index: distinfo
===================================================================
RCS file: /cvs/ports/lang/zig/distinfo,v
retrieving revision 1.16
diff -u -p -r1.16 distinfo
--- distinfo	11 May 2026 21:18:06 -0000	1.16
+++ distinfo	14 Jul 2026 20:02:33 -0000
@@ -1,2 +1,2 @@
-SHA256 (ziglang-zig-0.16.0.tar.gz) = CV10gwCOiF5l2Malf7l8VzRPmVQIpki41Q9hJ4rYXX8=
-SIZE (ziglang-zig-0.16.0.tar.gz) = 35262315
+SHA256 (ziglang-zig-0.16.0.tar.gz) = /b3OcQUn7dIBhXCYf8Kb2dbJ6CxRyykHudG9cMmT+l8=
+SIZE (ziglang-zig-0.16.0.tar.gz) = 35594555
Index: patches/patch-src_link_zig
===================================================================
RCS file: patches/patch-src_link_zig
diff -N patches/patch-src_link_zig
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_link_zig	14 Jul 2026 20:02:33 -0000
@@ -0,0 +1,67 @@
+Index: src/link.zig
+--- src/link.zig.orig
++++ src/link.zig
+@@ -2148,6 +2148,63 @@ fn resolveLibInput(
+         return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
+     }
+ 
++    // In the case of OpenBSD, dynamic libraries are always versioned, without
++    // unversioned symlinks, so we need to look for the highest-versioned shared
++    // library.
++    if (target.isOpenBSDLibC() and link_mode == .dynamic) versioned: {
++        const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name});
++
++        var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) {
++            error.NotDir, error.FileNotFound => break :versioned,
++            else => |e| fatal("unable to search for shared library '{s}.*': {s}", .{ prefix, @errorName(e) }),
++        };
++        defer dir.close(io);
++
++        var best_match_version = std.SemanticVersion{
++            .major = 0,
++            .minor = 0,
++            .patch = 0,
++        };
++        var best_match: ?[]const u8 = null;
++
++        var iter = dir.iterate();
++        while (iter.next(io) catch |err| {
++            fatal("unable to scan library directory '{s}'", .{@errorName(err)});
++        }) |entry| {
++            if (entry.kind != .file) continue;
++            if (!std.mem.startsWith(u8, entry.name, prefix)) continue;
++
++            const rest = entry.name[prefix.len..];
++            var sit = std.mem.splitScalar(u8, rest, '.');
++            const major_str = sit.next() orelse continue;
++            const minor_str = sit.next() orelse continue;
++            if (sit.next() != null) continue;
++            const major = std.fmt.parseInt(usize, major_str, 10) catch continue;
++            const minor = std.fmt.parseInt(usize, minor_str, 10) catch continue;
++
++            if (major > best_match_version.major or (major == best_match_version.major and minor >= best_match_version.minor)) {
++                best_match_version.major = major;
++                best_match_version.minor = minor;
++                best_match = try arena.dupe(u8, entry.name);
++            }
++        }
++
++        if (best_match) |found| {
++            const test_path: Path = .{
++                .root_dir = lib_directory,
++                .sub_path = found,
++            };
++            try checked_paths.print(gpa, "\n  {f}", .{test_path});
++            switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
++                .path = test_path,
++                .query = name_query.query,
++            }, link_mode, color)) {
++                .no_match => {},
++                .ok => return .ok,
++            }
++        }
++    }
++
+     return .no_match;
+ }
+ 

Reply via email to