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;
+ }
+