diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b9ce119b..241cb446 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,7 +1,7 @@ on: [push, pull_request] name: Test env: - ZIG_VERSION: 0.16.0 + ZIG_VERSION: 0.17.0 jobs: build: diff --git a/README.md b/README.md index 82d2eed3..778393c6 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ directory. # Build -Build requires the installation of the Zig 0.16. libxev follows stable +Build requires the installation of the Zig 0.17. libxev follows stable Zig releases and generally does not support nightly builds. When a stable release is imminent we may have a branch that supports it. **libxev has no other build dependencies.** diff --git a/build.zig b/build.zig index ee8d77ae..d40a5a1a 100644 --- a/build.zig +++ b/build.zig @@ -79,28 +79,25 @@ pub fn build(b: *std.Build) !void { ); // pkg-config - // FIXME: It is impossible since Zig 0.17 to obtain the - // installation prefix at the configure phase, as that - // is the responsibility of the maker. - // const pc: *Step.InstallFile = pc: { - // const file = b.addWriteFile("libxev.pc", b.fmt( - // \\prefix={s} - // \\includedir=${{prefix}}/include - // \\libdir=${{prefix}}/lib - // \\ - // \\Name: libxev - // \\URL: https://github.com/mitchellh/libxev - // \\Description: High-performance, cross-platform event loop - // \\Version: 0.1.0 - // \\Cflags: -I${{includedir}} - // \\Libs: -L${{libdir}} -lxev - // , .{b.install_prefix})); - // break :pc b.addInstallFileWithDir( - // file.getDirectory().path(b, "libxev.pc"), - // .prefix, - // "share/pkgconfig/libxev.pc", - // ); - // }; + const pc: *Step.InstallFile = pc: { + const file = b.addWriteFile("libxev.pc", b.fmt( + \\prefix=${{pcfiledir}}/../.. + \\includedir=${{prefix}}/include + \\libdir=${{prefix}}/lib + \\ + \\Name: libxev + \\URL: https://github.com/mitchellh/libxev + \\Description: High-performance, cross-platform event loop + \\Version: 0.1.0 + \\Cflags: -I${{includedir}} + \\Libs: -L${{libdir}} -lxev + , .{})); + break :pc b.addInstallFileWithDir( + file.getDirectory().path(b, "libxev.pc"), + .prefix, + "share/pkgconfig/libxev.pc", + ); + }; // Man pages const man = try manPages(b); @@ -141,7 +138,7 @@ pub fn build(b: *std.Build) !void { if (static_lib) |v| b.installArtifact(v); if (dynamic_lib) |v| b.installArtifact(v); b.getInstallStep().dependOn(&c_header.step); - // b.getInstallStep().dependOn(&pc.step); + b.getInstallStep().dependOn(&pc.step); b.installArtifact(test_exe); if (emit_man) { for (man) |step| b.getInstallStep().dependOn(step); @@ -173,6 +170,7 @@ fn buildBenchmarks( var steps: std.ArrayList(*Step.Compile) = .empty; defer steps.deinit(alloc); + b.dependOnDirectoryContents(b.path("src/bench")); var dir = try b.root.openDir(io, "src/bench", .{ .iterate = true }); defer dir.close(io); @@ -199,7 +197,7 @@ fn buildBenchmarks( .{entry.name}, )), .target = target, - .optimize = .ReleaseFast, // benchmarks are always release fast + .optimize = .fast, // benchmarks are always release fast }), }); exe.root_module.addImport("xev", b.modules.get("xev").?); @@ -214,7 +212,7 @@ fn buildBenchmarks( fn buildExamples( b: *std.Build, target: std.Build.ResolvedTarget, - optimize: std.builtin.OptimizeMode, + optimize: std.lang.Optimize, c_lib_: ?*Step.Compile, ) ![]const *Step.Compile { const io = b.graph.io; @@ -222,6 +220,7 @@ fn buildExamples( var steps: std.ArrayList(*Step.Compile) = .empty; defer steps.deinit(alloc); + b.dependOnDirectoryContents(b.path("examples")); var dir = try b.root.openDir(io, "examples", .{ .iterate = true }); defer dir.close(io); @@ -295,6 +294,7 @@ fn manPages(b: *std.Build) ![]const *Step { var steps: std.ArrayList(*Step) = .empty; defer steps.deinit(alloc); + b.dependOnDirectoryContents(b.path("docs")); var dir = try b.root.openDir(io, "docs", .{ .iterate = true }); defer dir.close(io); diff --git a/build.zig.zon b/build.zig.zon index cf53cc88..c7a540bd 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .libxev, - .minimum_zig_version = "0.16.0", + .minimum_zig_version = "0.17.0", .version = "0.0.0", .fingerprint = 0x30f7363573edabf3, .paths = .{""}, diff --git a/flake.lock b/flake.lock index 31c54065..1cb74e59 100644 --- a/flake.lock +++ b/flake.lock @@ -107,11 +107,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1776398705, - "narHash": "sha256-/RYhj2fmbFWjfNORGjI18rJzLICNahxPSy0epCdyVRk=", + "lastModified": 1790988737, + "narHash": "sha256-b55etI4Uxu+WHhYZXym3HPIz63ipO9lqwJLAphjqtTc=", "owner": "mitchellh", "repo": "zig-overlay", - "rev": "e2956eb5a19f92fef466f1af78f1fb8c207767af", + "rev": "dcffc7a25ed2cbbc7c1c3c448c312abf46ae6cb8", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index c5eb1367..aa1b8991 100644 --- a/flake.nix +++ b/flake.nix @@ -23,7 +23,7 @@ # Other overlays (final: prev: rec { zigpkgs = inputs.zig.packages.${prev.system}; - zig = inputs.zig.packages.${prev.system}."0.16.0"; + zig = inputs.zig.packages.${prev.system}."0.17.0"; # Our package libxev = prev.callPackage ./nix/package.nix {}; diff --git a/nix/package.nix b/nix/package.nix index 4817154d..c337c0b1 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -30,6 +30,13 @@ stdenv.mkDerivation rec { outputs = [ "out" "dev" "man" ]; + # libxev.pc locates its prefix from where it sits, and the dev output keeps + # it apart from the libraries in $out. + postFixup = '' + substituteInPlace $dev/share/pkgconfig/libxev.pc \ + --replace-fail 'prefix=''${pcfiledir}/../..' "prefix=$out" + ''; + meta = with lib; { description = "A high performance, cross-platform event loop."; homepage = "https://github.com/mitchellh/libxev"; diff --git a/src/backend/io_uring.zig b/src/backend/io_uring.zig index b420971b..3892e9ef 100644 --- a/src/backend/io_uring.zig +++ b/src/backend/io_uring.zig @@ -667,7 +667,7 @@ pub const Completion = struct { .accept => .{ .accept = if (res >= 0) @intCast(res) - else switch (@as(posix.E, @enumFromInt(-res))) { + else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, .AGAIN => error.Again, else => |errno| posix.unexpectedErrno(errno), @@ -675,13 +675,13 @@ pub const Completion = struct { }, .close => .{ - .close = if (res >= 0) {} else switch (@as(posix.E, @enumFromInt(-res))) { + .close = if (res >= 0) {} else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { else => |errno| posix.unexpectedErrno(errno), }, }, .connect => .{ - .connect = if (res >= 0) {} else switch (@as(posix.E, @enumFromInt(-res))) { + .connect = if (res >= 0) {} else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, .CONNREFUSED => error.ConnectionRefused, .TIMEDOUT => error.TimedOut, @@ -691,7 +691,7 @@ pub const Completion = struct { }, .poll => .{ - .poll = if (res >= 0) {} else switch (@as(posix.E, @enumFromInt(-res))) { + .poll = if (res >= 0) {} else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { else => |errno| posix.unexpectedErrno(errno), }, }, @@ -715,7 +715,7 @@ pub const Completion = struct { .send => .{ .send = if (res >= 0) @intCast(res) - else switch (@as(posix.E, @enumFromInt(-res))) { + else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, .PIPE => error.BrokenPipe, .CONNRESET => error.ConnectionResetByPeer, @@ -726,7 +726,7 @@ pub const Completion = struct { .sendmsg => .{ .sendmsg = if (res >= 0) @intCast(res) - else switch (@as(posix.E, @enumFromInt(-res))) { + else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, .PIPE => error.BrokenPipe, .CONNRESET => error.ConnectionResetByPeer, @@ -735,7 +735,7 @@ pub const Completion = struct { }, .shutdown => .{ - .shutdown = if (res >= 0) {} else switch (@as(posix.E, @enumFromInt(-res))) { + .shutdown = if (res >= 0) {} else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, .NOTCONN => error.SocketNotConnected, else => |errno| posix.unexpectedErrno(errno), @@ -743,7 +743,7 @@ pub const Completion = struct { }, .timer => |*op| timer: { - const e = @as(posix.E, @enumFromInt(-res)); + const e = @as(posix.E, @fromBackingInt(@intCast(-res))); // If we have reset set, that means that we were canceled so // that we can update our expiration time. @@ -763,7 +763,7 @@ pub const Completion = struct { }, .timer_remove => .{ - .timer_remove = if (res >= 0) {} else switch (@as(posix.E, @enumFromInt(-res))) { + .timer_remove = if (res >= 0) {} else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .NOENT => error.NotFound, .BUSY => error.ExpirationInProgress, @@ -781,7 +781,7 @@ pub const Completion = struct { .write => .{ .write = if (res >= 0) @intCast(res) - else switch (@as(posix.E, @enumFromInt(-res))) { + else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, // If a write is interrupted, we retry it automatically. .INTR => return .rearm, @@ -792,7 +792,7 @@ pub const Completion = struct { .pwrite => .{ .pwrite = if (res >= 0) @intCast(res) - else switch (@as(posix.E, @enumFromInt(-res))) { + else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, // If a write is interrupted, we retry it automatically. .INTR => return .rearm, @@ -801,7 +801,7 @@ pub const Completion = struct { }, .cancel => .{ - .cancel = if (res >= 0) {} else switch (@as(posix.E, @enumFromInt(-res))) { + .cancel = if (res >= 0) {} else switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .NOENT => error.NotFound, .ALREADY => error.ExpirationInProgress, else => |errno| posix.unexpectedErrno(errno), @@ -829,7 +829,7 @@ pub const Completion = struct { }; } - return switch (@as(posix.E, @enumFromInt(-res))) { + return switch (@as(posix.E, @fromBackingInt(@intCast(-res)))) { .CANCELED => error.Canceled, .CONNRESET => error.ConnectionResetByPeer, else => |errno| posix.unexpectedErrno(errno), diff --git a/src/backend/iocp.zig b/src/backend/iocp.zig index cc8506ea..be17a62e 100644 --- a/src/backend/iocp.zig +++ b/src/backend/iocp.zig @@ -357,7 +357,7 @@ pub const Loop = struct { const completion: *Completion = @ptrFromInt(entry.lpCompletionKey); completion.result = .{ .job_object = .{ .message = .{ - .type = @enumFromInt(entry.dwNumberOfBytesTransferred), + .type = @fromBackingInt(@intCast(entry.dwNumberOfBytesTransferred)), .value = @intFromPtr(entry.lpOverlapped), }, } }; diff --git a/src/backend/kqueue.zig b/src/backend/kqueue.zig index a78249dd..ed28c9a0 100644 --- a/src/backend/kqueue.zig +++ b/src/backend/kqueue.zig @@ -1292,7 +1292,7 @@ pub const Completion = struct { /// in the situation that kqueue fails to enqueue the completion or /// a raw syscall fails. fn syscall_result(c: *Completion, r: i32) Result { - const errno: posix.E = if (r >= 0) .SUCCESS else @enumFromInt(-r); + const errno: posix.E = if (r >= 0) .SUCCESS else @fromBackingInt(@intCast(-r)); return switch (c.op) { .noop => unreachable, @@ -1553,7 +1553,7 @@ fn getsockoptError(socket: posix.socket_t) ConnectError!void { } if (err_code == 0) return; - return switch (@as(posix.E, @enumFromInt(@as(u16, @intCast(err_code))))) { + return switch (@as(posix.E, @fromBackingInt(@intCast(@as(u16, @intCast(err_code)))))) { .ADDRNOTAVAIL => error.AddressUnavailable, .AFNOSUPPORT => error.AddressFamilyUnsupported, .ACCES, .PERM => error.AccessDenied, @@ -1926,7 +1926,7 @@ fn kevent_syscall( /// Converts a posix errno to the negative i32 format expected by syscall_result. inline fn errno_to_result(errno: posix.E) i32 { - return -@as(i32, @intCast(@intFromEnum(errno))); + return -@as(i32, @intCast(@backingInt(errno))); } /// kevent_init initializes a Kevent from a std.c.Kevent. This is used when @@ -2714,7 +2714,7 @@ test "kqueue: mach port" { // Send a message to the port var msg: darwin.mach_msg_header_t = .{ - .msgh_bits = @intFromEnum(posix.system.MACH.MSG.TYPE.MAKE_SEND_ONCE), + .msgh_bits = @backingInt(posix.system.MACH.MSG.TYPE.MAKE_SEND_ONCE), .msgh_size = @sizeOf(darwin.mach_msg_header_t), .msgh_remote_port = mach_port, .msgh_local_port = darwin.MACH_PORT_NULL, @@ -2829,7 +2829,7 @@ test "kqueue: timer armed from delayed callback must not fire early" { ) catch unreachable; var msg: darwin.mach_msg_header_t = .{ - .msgh_bits = @intFromEnum(posix.system.MACH.MSG.TYPE.MAKE_SEND_ONCE), + .msgh_bits = @backingInt(posix.system.MACH.MSG.TYPE.MAKE_SEND_ONCE), .msgh_size = @sizeOf(darwin.mach_msg_header_t), .msgh_remote_port = port, .msgh_local_port = darwin.MACH_PORT_NULL, diff --git a/src/bench/ping-pongs.zig b/src/bench/ping-pongs.zig index 3a8c4f86..9b18515c 100644 --- a/src/bench/ping-pongs.zig +++ b/src/bench/ping-pongs.zig @@ -4,8 +4,6 @@ const Allocator = std.mem.Allocator; const xev = @import("xev"); //const xev = @import("xev").Dynamic; - - pub const std_options: std.Options = .{ .log_level = .info, }; diff --git a/src/darwin.zig b/src/darwin.zig index 6f95c2e0..292fc4bd 100644 --- a/src/darwin.zig +++ b/src/darwin.zig @@ -67,7 +67,7 @@ pub extern "c" fn mach_msg( ) std.c.kern_return_t; pub fn getKernError(err: std.c.kern_return_t) KernE { - return @as(KernE, @enumFromInt(@as(u32, @truncate(@as(usize, @intCast(err)))))); + return @as(KernE, @fromBackingInt(@intCast(@as(u32, @truncate(@as(usize, @intCast(err))))))); } /// Kernel return values @@ -291,7 +291,7 @@ pub const KernE = enum(u32) { }; pub fn getMachMsgError(err: mach_msg_return_t) MachMsgE { - return @as(MachMsgE, @enumFromInt(@as(u32, @truncate(@as(usize, @intCast(err)))))); + return @as(MachMsgE, @fromBackingInt(@intCast(@as(u32, @truncate(@as(usize, @intCast(err))))))); } /// Mach msg return values diff --git a/src/dynamic.zig b/src/dynamic.zig index 547abb94..66e47809 100644 --- a/src/dynamic.zig +++ b/src/dynamic.zig @@ -176,11 +176,11 @@ pub fn Xev(comptime bes: []const AllBackend) type { /// Helpers to convert between the subset/superset of backends. pub fn subset(comptime be: AllBackend) Backend { - return @enumFromInt(@intFromEnum(be)); + return @fromBackingInt(@intCast(@backingInt(be))); } pub fn superset(comptime be: Backend) AllBackend { - return @enumFromInt(@intFromEnum(be)); + return @fromBackingInt(@intCast(@backingInt(be))); } pub fn Union(comptime field: []const []const u8) type { @@ -208,7 +208,7 @@ pub fn Xev(comptime bes: []const AllBackend) type { const testing = std.testing; try detect(); inline for (bes) |be| { - if (@intFromEnum(be) == @intFromEnum(backend)) { + if (@backingInt(be) == @backingInt(backend)) { try testing.expect(be.Api().available()); break; } @@ -219,7 +219,7 @@ pub fn Xev(comptime bes: []const AllBackend) type { const testing = std.testing; try testing.expect(prefer(bes[0])); inline for (bes) |be| { - if (@intFromEnum(be) == @intFromEnum(backend)) { + if (@backingInt(be) == @backingInt(backend)) { try testing.expect(be.Api().available()); break; } @@ -432,7 +432,7 @@ fn EnumSubset(comptime T: type, comptime values: []const T) type { var field_values: [values.len]tag_type = undefined; for (values, 0..) |value, i| { field_names[i] = @tagName(value); - field_values[i] = @intFromEnum(value); + field_values[i] = @backingInt(value); } return @Enum(tag_type, .exhaustive, &field_names, &field_values); diff --git a/src/posix.zig b/src/posix.zig index 81e32104..300bd46b 100644 --- a/src/posix.zig +++ b/src/posix.zig @@ -252,7 +252,7 @@ pub fn getsockoptError(sockfd: posix.fd_t) ConnectError!void { const rc = system.getsockopt(sockfd, SOL.SOCKET, SO.ERROR, @ptrCast(&err_code), &size); std.debug.assert(size == 4); switch (posix.errno(rc)) { - .SUCCESS => switch (@as(E, @enumFromInt(err_code))) { + .SUCCESS => switch (@as(E, @fromBackingInt(@intCast(err_code)))) { .SUCCESS => return, .ACCES => return error.AccessDenied, .PERM => return error.PermissionDenied, diff --git a/src/watcher/async.zig b/src/watcher/async.zig index be27d45f..3d147512 100644 --- a/src/watcher/async.zig +++ b/src/watcher/async.zig @@ -402,7 +402,7 @@ fn AsyncMachPort(comptime xev: type) type { var msg: darwin.mach_msg_header_t = .{ // We use COPY_SEND which will not increment any send ref // counts because it'll reuse the existing send right. - .msgh_bits = @intFromEnum(posix.system.MACH.MSG.TYPE.COPY_SEND), + .msgh_bits = @backingInt(posix.system.MACH.MSG.TYPE.COPY_SEND), .msgh_size = @sizeOf(darwin.mach_msg_header_t), .msgh_remote_port = self.port, .msgh_local_port = darwin.MACH_PORT_NULL, diff --git a/src/watcher/file.zig b/src/watcher/file.zig index 3ccbcb02..24e00ee4 100644 --- a/src/watcher/file.zig +++ b/src/watcher/file.zig @@ -633,13 +633,12 @@ fn FileTests( ) type { return struct { test "File: Stream decls" { - if (!@hasDecl(Impl, "S")) return; const Stream = Impl.S; - inline for (@typeInfo(Stream).@"struct".decls) |decl| { - const Decl = @TypeOf(@field(Stream, decl.name)); + inline for (@typeInfo(Stream).@"struct".decl_names) |decl_name| { + const Decl = @TypeOf(@field(Stream, decl_name)); if (Decl == void) continue; - if (!@hasDecl(Impl, decl.name)) { - @compileError("missing decl: " ++ decl.name); + if (!@hasDecl(Impl, decl_name)) { + @compileError("missing decl: " ++ decl_name); } } } diff --git a/src/watcher/stream.zig b/src/watcher/stream.zig index 736935a6..a9f10a4a 100644 --- a/src/watcher/stream.zig +++ b/src/watcher/stream.zig @@ -87,7 +87,7 @@ pub fn Shared(comptime xev: type) type { .io_uring, .epoll, => if (result.poll) |_| - @enumFromInt(c.op.poll.events) + @fromBackingInt(@intCast(c.op.poll.events)) else |err| err, @@ -1132,12 +1132,11 @@ pub fn GenericStream(comptime xev: type) type { fn GenericStreamTests(comptime xev: type, comptime Impl: type) type { return struct { test "Stream decls" { - if (!@hasDecl(Impl, "S")) return; - inline for (@typeInfo(Impl.S).@"struct".decls) |decl| { - const Decl = @TypeOf(@field(Impl.S, decl.name)); + inline for (@typeInfo(Impl.S).@"struct".decl_names) |decl_name| { + const Decl = @TypeOf(@field(Impl.S, decl_name)); if (Decl == void) continue; - if (!@hasDecl(Impl, decl.name)) { - @compileError("missing decl: " ++ decl.name); + if (!@hasDecl(Impl, decl_name)) { + @compileError("missing decl: " ++ decl_name); } } } diff --git a/src/watcher/tcp.zig b/src/watcher/tcp.zig index 1340b1e6..b4f66fa8 100644 --- a/src/watcher/tcp.zig +++ b/src/watcher/tcp.zig @@ -518,13 +518,12 @@ fn TCPDynamic(comptime xev: type) type { fn TCPTests(comptime xev: type, comptime Impl: type) type { return struct { test "TCP: Stream decls" { - if (!@hasDecl(Impl, "S")) return; const Stream = Impl.S; - inline for (@typeInfo(Stream).@"struct".decls) |decl| { - const Decl = @TypeOf(@field(Stream, decl.name)); + inline for (@typeInfo(Stream).@"struct".decl_names) |decl_name| { + const Decl = @TypeOf(@field(Stream, decl_name)); if (Decl == void) continue; - if (!@hasDecl(Impl, decl.name)) { - @compileError("missing decl: " ++ decl.name); + if (!@hasDecl(Impl, decl_name)) { + @compileError("missing decl: " ++ decl_name); } } } diff --git a/src/watcher/udp.zig b/src/watcher/udp.zig index a480e9ed..4a831cd9 100644 --- a/src/watcher/udp.zig +++ b/src/watcher/udp.zig @@ -913,13 +913,12 @@ fn UDPDynamic(comptime xev: type) type { fn UDPTests(comptime xev: type, comptime Impl: type) type { return struct { test "UDP: Stream decls" { - if (!@hasDecl(Impl, "S")) return; const Stream = Impl.S; - inline for (@typeInfo(Stream).@"struct".decls) |decl| { - const Decl = @TypeOf(@field(Stream, decl.name)); + inline for (@typeInfo(Stream).@"struct".decl_names) |decl_name| { + const Decl = @TypeOf(@field(Stream, decl_name)); if (Decl == void) continue; - if (!@hasDecl(Impl, decl.name)) { - @compileError("missing decl: " ++ decl.name); + if (!@hasDecl(Impl, decl_name)) { + @compileError("missing decl: " ++ decl_name); } } } diff --git a/src/windows.zig b/src/windows.zig index 8ddbe3a3..3d4eb3b8 100644 --- a/src/windows.zig +++ b/src/windows.zig @@ -459,7 +459,7 @@ pub const ws2_32 = struct { // --- High-level wrapper functions --- pub fn unexpectedWSAError(err: ws2_32.WinsockError) error{Unexpected} { - return unexpectedError(@as(Win32Error, @enumFromInt(@intFromEnum(err)))); + return unexpectedError(@as(Win32Error, @fromBackingInt(@intCast(@backingInt(err))))); } pub fn QueryPerformanceCounter() u64 {