diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2e67b02..9646251 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,3 +24,7 @@ jobs: - name: Build run: zig build --summary all + + - name: Build for FreeBSD + run: | + zig build -Dtarget=native-freebsd --summary all diff --git a/README.md b/README.md index 0cde7c7..9785e92 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ const wayland_cursor = wayland.artifact("wayland-cursor"); // Makes sure we get `wayland-scanner` for the host platform even when cross-compiling const wayland_host = b.dependency("wayland", .{ - .target = b.host, + .target = b.graph.host, .optimize = std.builtin.OptimizeMode.Debug, }); const wayland_scanner = wayland_host.artifact("wayland-scanner"); diff --git a/build.zig b/build.zig index b74a9c7..5580c3a 100644 --- a/build.zig +++ b/build.zig @@ -14,13 +14,15 @@ pub fn build(b: *std.Build) void { const dtd_validation = b.option(bool, "dtd-validation", "Validate the protocol DTD") orelse true; const icon_directory = b.option([]const u8, "icon-directory", "Location used to look for cursors (defaults to ${datadir}/icons if unset)"); + const link_system_expat = b.systemIntegrationOption("expat", .{}); + const link_system_ffi = b.systemIntegrationOption("ffi", .{}); + const link_system_epoll_shim = b.systemIntegrationOption("epoll-shim", .{}); + const need_epoll_shim = switch (target.result.os.tag) { .freebsd, .openbsd => true, else => false, }; - - const link_system_expat = b.systemIntegrationOption("expat", .{}); - const link_system_ffi = b.systemIntegrationOption("ffi", .{}); + const epoll_shim = if (need_epoll_shim and !link_system_epoll_shim) createEpollShim(b, target, optimize) else null; const cc_flags = getCCFlags(b, target); const host_cc_flags = getCCFlags(b, b.graph.host); @@ -72,26 +74,21 @@ pub fn build(b: *std.Build) void { .PACKAGE = "wayland", .PACKAGE_VERSION = b.fmt("{f}", .{version}), .HAVE_SYS_PRCTL_H = target.result.os.tag == .linux, - .HAVE_SYS_PROCCTL_H = target.result.os.isAtLeast(.freebsd, .{ .major = 10, .minor = 0, .patch = 0 }), + .HAVE_SYS_PROCCTL_H = target.result.os.isAtLeast(.freebsd, .{ .major = 10, .minor = 0, .patch = 0 }) orelse false, .HAVE_SYS_UCRED_H = target.result.os.tag.isBSD(), .HAVE_ACCEPT4 = true, - // libffi also has `HAVE_MKOSTEMP` but doesn't check the glibc version - .HAVE_MKOSTEMP = if (target.result.isMuslLibC()) - true - else if (target.result.isGnuLibC()) - target.result.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 7, .patch = 0 }) != .lt - else - unreachable, + .HAVE_MKOSTEMP = switch (target.result.os.tag) { + .linux => target.result.isMuslLibC() or (target.result.isGnuLibC() and target.result.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 7, .patch = 0 }) != .lt), + .freebsd => target.result.os.isAtLeast(.freebsd, .{ .major = 10, .minor = 0, .patch = 0 }) orelse false, + else => false, + }, .HAVE_POSIX_FALLOCATE = true, .HAVE_PRCTL = target.result.os.tag == .linux, + // libffi also has `HAVE_MEMFD_CREATE` but doesn't check the glibc version .HAVE_MEMFD_CREATE = switch (target.result.os.tag) { - .linux => if (target.result.isMuslLibC()) - true - else if (target.result.isGnuLibC()) - target.result.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 27, .patch = 0 }) != .lt - else - unreachable, + .linux => target.result.isMuslLibC() or (target.result.isGnuLibC() and target.result.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 7, .patch = 0 }) != .lt), .freebsd => target.result.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false, + .netbsd => target.result.os.version_range.semver.isAtLeast(.{ .major = 11, .minor = 0, .patch = 0 }) orelse false, else => false, }, .HAVE_MREMAP = target.result.os.tag == .linux or target.result.os.tag == .freebsd, @@ -106,8 +103,8 @@ pub fn build(b: *std.Build) void { const wayland_private = blk: { const write_files = b.addWriteFiles(); - _ = write_files.addCopyFile(wayland_header.getOutput(), "config.h"); - const wayland_header2 = write_files.addCopyFile(wayland_header.getOutput(), "config/config.h"); + _ = write_files.addCopyFile(wayland_header.getOutputFile(), "config.h"); + const wayland_header2 = write_files.addCopyFile(wayland_header.getOutputFile(), "config/config.h"); const wayland_private = b.addLibrary(.{ .linkage = .static, @@ -128,7 +125,13 @@ pub fn build(b: *std.Build) void { .root = upstream.path("src"), .flags = cc_flags, }); - if (need_epoll_shim) wayland_private.root_module.linkSystemLibrary("epoll-shim", .{}); + if (need_epoll_shim) { + if (link_system_epoll_shim) { + wayland_private.root_module.linkSystemLibrary("epoll-shim", .{}); + } else { + if (epoll_shim) |compile| wayland_private.root_module.linkLibrary(compile); + } + } wayland_private.root_module.linkSystemLibrary("rt", .{}); if (link_system_ffi) { wayland_private.root_module.linkSystemLibrary("ffi", .{}); @@ -224,7 +227,13 @@ pub fn build(b: *std.Build) void { .root = upstream.path("src"), .flags = cc_flags, }); - if (need_epoll_shim) wayland_server.root_module.linkSystemLibrary("epoll-shim", .{}); + if (need_epoll_shim) { + if (link_system_epoll_shim) { + wayland_server.root_module.linkSystemLibrary("epoll-shim", .{}); + } else { + if (epoll_shim) |compile| wayland_server.root_module.linkLibrary(compile); + } + } wayland_server.root_module.linkSystemLibrary("rt", .{}); if (link_system_ffi) { wayland_server.root_module.linkSystemLibrary("ffi", .{}); @@ -274,7 +283,13 @@ pub fn build(b: *std.Build) void { .flags = cc_flags, }); - if (need_epoll_shim) wayland_client.root_module.linkSystemLibrary("epoll-shim", .{}); + if (need_epoll_shim) { + if (link_system_epoll_shim) { + wayland_client.root_module.linkSystemLibrary("epoll-shim", .{}); + } else { + if (epoll_shim) |compile| wayland_client.root_module.linkLibrary(compile); + } + } wayland_client.root_module.linkSystemLibrary("rt", .{}); if (link_system_ffi) { wayland_client.root_module.linkSystemLibrary("ffi", .{}); @@ -458,6 +473,100 @@ fn getCCFlags(b: *std.Build, target: std.Build.ResolvedTarget) []const []const u return cc_flags_list.items; } +fn createEpollShim( + b: *std.Build, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, +) ?*std.Build.Step.Compile { + const upstream = b.lazyDependency("epoll-shim", .{}) orelse return null; + + const have_eventfd = switch (target.result.os.tag) { + .freebsd => target.result.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false, + .netbsd => target.result.os.isAtLeast(.netbsd, .{ .major = 10, .minor = 0, .patch = 0 }) orelse false, + .openbsd => false, + else => unreachable, + }; + const have_timerfd = switch (target.result.os.tag) { + .freebsd => target.result.os.isAtLeast(.freebsd, .{ .major = 12, .minor = 0, .patch = 0 }) orelse false, + .netbsd => target.result.os.isAtLeast(.netbsd, .{ .major = 10, .minor = 0, .patch = 0 }) orelse false, + .openbsd => false, + else => unreachable, + }; + const have_errno_t = switch (target.result.os.tag) { + .netbsd => false, + .freebsd, .openbsd => true, + else => unreachable, + }; + + const flags: []const []const u8 = &.{ + "-fvisibility=hidden", + "-std=gnu11", + }; + + const epoll_shim = b.addLibrary(.{ + .name = "epoll-shim", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }), + }); + + for ([_][]const u8{ + "epoll-shim/detail/common.h", + "epoll-shim/detail/poll.h", + "epoll-shim/detail/read.h", + "epoll-shim/detail/write.h", + "sys/epoll.h", + "sys/signalfd.h", + }) |path| { + const config_header = b.addConfigHeader(.{ + .include_path = path, + .style = .{ .cmake = upstream.path("include").path(b, path) }, + }, .{ + .POLLRDHUP_VALUE = @as(i64, if (target.result.isFreeBSDLibC()) 0x4000 else 0x2000), + }); + epoll_shim.installConfigHeader(config_header); + epoll_shim.root_module.addConfigHeader(config_header); + } + epoll_shim.root_module.linkSystemLibrary("pthread", .{}); + epoll_shim.root_module.linkSystemLibrary("rt", .{}); + epoll_shim.root_module.addCMacro("EPOLL_SHIM_DISABLE_WRAPPER_MACROS", ""); + epoll_shim.root_module.addIncludePath(b.path("")); + epoll_shim.root_module.addIncludePath(upstream.path("external/queue-macros/include")); + epoll_shim.root_module.addIncludePath(upstream.path("external/tree-macros/include/sys")); + epoll_shim.root_module.addCSourceFiles(.{ + .root = upstream.path("src"), + .files = &.{ + "epoll_shim_ctx.c", + "epoll.c", + "epollfd_ctx.c", + "kqueue_event.c", + "signalfd.c", + "signalfd_ctx.c", + "timespec_util.c", + "rwlock.c", + "wrap.c", + }, + .flags = flags, + }); + if (!have_eventfd) { + epoll_shim.installHeader(upstream.path("include/sys/eventfd.h"), "sys/eventfd.h"); + epoll_shim.root_module.addCSourceFile(.{ .file = upstream.path("src/eventfd.c"), .flags = flags }); + epoll_shim.root_module.addCSourceFile(.{ .file = upstream.path("src/eventfd_ctx.c"), .flags = flags }); + } + if (!have_timerfd) { + epoll_shim.installHeader(upstream.path("include/sys/timerfd.h"), "sys/timerfd.h"); + epoll_shim.root_module.addCSourceFile(.{ .file = upstream.path("src/timerfd.c"), .flags = flags }); + epoll_shim.root_module.addCSourceFile(.{ .file = upstream.path("src/timerfd_ctx.c"), .flags = flags }); + } else { + epoll_shim.root_module.addCMacro("HAVE_TIMERFD", ""); + } + if (!have_errno_t) epoll_shim.root_module.addCMacro("errno_t", "int"); + + return epoll_shim; +} + comptime { if (version.major != 1) { // The versioning used for the shared libraries assumes that the major diff --git a/build.zig.zon b/build.zig.zon index c7b5849..d33ef3e 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,25 +1,30 @@ .{ .name = .wayland, .version = "1.24.0-2", - .minimum_zig_version = "0.15.1", + .minimum_zig_version = "0.15.2", .dependencies = .{ .wayland = .{ .url = "git+https://gitlab.freedesktop.org/wayland/wayland.git?ref=1.24#736d12ac67c20c60dc406dc49bb06be878501f86", .hash = "N-V-__8AAGoeGQBEn6KguTJUXrCE0tIRrrXfQX7hYHoKCJwZ", }, .libffi = .{ - .url = "git+https://codeberg.org/vezel/libffi.git#3aac158d09755844f1d9892e86512e9afbbd6c37", - .hash = "libffi-3.5.2-7_tEtNc5FwAWDaCWKtJ6Mh4eEWn8poybcaMRLhIOtag8", + .url = "git+https://codeberg.org/vezel/libffi.git?ref=v3.5.2-3#e972331ede2dc7ca107b6c3d3998c3b66bcab4db", + .hash = "libffi-3.5.2-7_tEtCY7FwBjSWOed_hvKoIb_otUeege34q9FpLH_03N", .lazy = true, }, .libexpat = .{ - .url = "git+https://github.com/allyourcodebase/libexpat.git?ref=2.7.1-1#472c1db660c813a952f235cb394f5997d2e83fe1", - .hash = "libexpat-2.7.1-1-y_akI-w7AABhqRN54g--MNNIR-zA1X2WZ36ZPriY84sb", + .url = "git+https://github.com/allyourcodebase/libexpat.git?ref=2.7.1-2#d0bb4a56bff357fb478988ade0f94a426490c4d8", + .hash = "libexpat-2.7.1-2-y_akI-47AAB-pppMdnxv9vkgNyerxr4IyfmHdz3aMtUm", .lazy = true, }, .libxml2 = .{ - .url = "git+https://github.com/allyourcodebase/libxml2.git?ref=2.15.1-1#236bcdeaa52f9743593fa2d1f36e93f8796c25e8", - .hash = "libxml2-2.15.1-1-qHdjhl9MAACMrhlLwgk80e6_KjaK4ZqabFa7jkBPxLQO", + .url = "git+https://github.com/allyourcodebase/libxml2.git?ref=2.15.1-2#2528fad1bf17a0a70999930cfd9280554f547787", + .hash = "libxml2-2.15.1-2-qHdjhmNMAAAiZOWqVridicq2oMf5NHv0n9W41bz9FtMM", + .lazy = true, + }, + .@"epoll-shim" = .{ + .url = "git+https://github.com/jiixyj/epoll-shim.git#18159584bb3d17e601b9315a7398ace018251bdc", + .hash = "N-V-__8AAJHtBwDe4gR5ofaikfFsHj0vPE-uTQSAkqY2uRv_", .lazy = true, }, }, diff --git a/epoll_shim_export.h b/epoll_shim_export.h new file mode 100644 index 0000000..5dbb02b --- /dev/null +++ b/epoll_shim_export.h @@ -0,0 +1,43 @@ + +#ifndef EPOLL_SHIM_EXPORT_H +#define EPOLL_SHIM_EXPORT_H + +#ifdef EPOLL_SHIM_STATIC_DEFINE +# define EPOLL_SHIM_EXPORT +# define EPOLL_SHIM_NO_EXPORT +#else +# ifndef EPOLL_SHIM_EXPORT +# ifdef epoll_shim_EXPORTS + /* We are building this library */ +# define EPOLL_SHIM_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define EPOLL_SHIM_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef EPOLL_SHIM_NO_EXPORT +# define EPOLL_SHIM_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef EPOLL_SHIM_DEPRECATED +# define EPOLL_SHIM_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef EPOLL_SHIM_DEPRECATED_EXPORT +# define EPOLL_SHIM_DEPRECATED_EXPORT EPOLL_SHIM_EXPORT EPOLL_SHIM_DEPRECATED +#endif + +#ifndef EPOLL_SHIM_DEPRECATED_NO_EXPORT +# define EPOLL_SHIM_DEPRECATED_NO_EXPORT EPOLL_SHIM_NO_EXPORT EPOLL_SHIM_DEPRECATED +#endif + +/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */ +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef EPOLL_SHIM_NO_DEPRECATED +# define EPOLL_SHIM_NO_DEPRECATED +# endif +#endif + +#endif /* EPOLL_SHIM_EXPORT_H */