summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--build.zig9
-rw-r--r--src/libuv/Loop.zig53
-rw-r--r--src/libuv/build.zig132
-rw-r--r--src/libuv/c.zig3
-rw-r--r--src/libuv/error.zig185
-rw-r--r--src/libuv/main.zig7
-rw-r--r--src/main.zig3
m---------vendor/libuv0
9 files changed, 390 insertions, 5 deletions
diff --git a/.gitmodules b/.gitmodules
index 28095252a..eee2a129c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,6 @@
[submodule "vendor/cglm"]
path = vendor/cglm
url = https://github.com/recp/cglm.git
+[submodule "vendor/libuv"]
+ path = vendor/libuv
+ url = https://github.com/libuv/libuv.git
diff --git a/build.zig b/build.zig
index 18ea397f5..2de72a81e 100644
--- a/build.zig
+++ b/build.zig
@@ -3,6 +3,7 @@ const Builder = std.build.Builder;
const LibExeObjStep = std.build.LibExeObjStep;
const glfw = @import("vendor/mach/glfw/build.zig");
const ft = @import("src/freetype/build.zig");
+const uv = @import("src/libuv/build.zig");
pub fn build(b: *std.build.Builder) !void {
const target = b.standardTargetOptions(.{});
@@ -23,11 +24,8 @@ pub fn build(b: *std.build.Builder) !void {
const ftlib = try ft.create(b, target, mode, .{});
ftlib.link(exe);
- // to link to system:
- // exe.linkSystemLibrary("freetype2");
- // exe.linkSystemLibrary("libpng");
- // exe.linkSystemLibrary("bzip2");
- // ftlib.addIncludeDirs(exe);
+
+ const libuv = try uv.create(b, target, mode);
// stb if we need it
// exe.addIncludeDir("vendor/stb");
@@ -46,6 +44,7 @@ pub fn build(b: *std.build.Builder) !void {
const test_step = b.step("test", "Run all tests");
const lib_tests = b.addTest("src/main.zig");
ftlib.link(lib_tests);
+ libuv.link(lib_tests);
lib_tests.addIncludeDir("vendor/glad/include/");
lib_tests.addCSourceFile("vendor/glad/src/gl.c", &.{});
test_step.dependOn(&lib_tests.step);
diff --git a/src/libuv/Loop.zig b/src/libuv/Loop.zig
new file mode 100644
index 000000000..b748e9899
--- /dev/null
+++ b/src/libuv/Loop.zig
@@ -0,0 +1,53 @@
+const Loop = @This();
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const testing = std.testing;
+const c = @import("c.zig");
+const errors = @import("error.zig");
+
+loop: *c.uv_loop_t,
+
+/// Initialize a new uv_loop.
+pub fn init(alloc: Allocator) !Loop {
+ // The uv_loop_t type MUST be heap allocated and must not be copied.
+ // I can't find a definitive source on this, but the test suite starts
+ // hanging in weird places and doing bad things when it is copied.
+ const loop = try alloc.create(c.uv_loop_t);
+ try errors.convertError(c.uv_loop_init(loop));
+ return Loop{ .loop = loop };
+}
+
+/// Releases all internal loop resources. Call this function only when the
+/// loop has finished executing and all open handles and requests have been
+/// closed, or this will silently fail (in debug mode it will panic).
+pub fn deinit(self: *Loop, alloc: Allocator) void {
+ // deinit functions idiomatically cannot fail in Zig, so we do the
+ // next best thing here and assert so that in debug mode you'll get
+ // a crash.
+ std.debug.assert(c.uv_loop_close(self.loop) >= 0);
+ alloc.destroy(self.loop);
+ self.* = undefined;
+}
+
+/// This function runs the event loop. See RunMode for mode documentation.
+///
+/// This is not reentrant. It must not be called from a callback.
+pub fn run(self: *Loop, mode: RunMode) !u32 {
+ const res = c.uv_run(self.loop, @enumToInt(mode));
+ try errors.convertError(res);
+ return @intCast(u32, res);
+}
+
+/// Mode used to run the loop with uv_run().
+pub const RunMode = enum(c.uv_run_mode) {
+ default = c.UV_RUN_DEFAULT,
+ once = c.UV_RUN_ONCE,
+ nowait = c.UV_RUN_NOWAIT,
+};
+
+test {
+ var loop = try init(testing.allocator);
+ defer loop.deinit(testing.allocator);
+ try testing.expectEqual(@as(u32, 0), try loop.run(.nowait));
+}
diff --git a/src/libuv/build.zig b/src/libuv/build.zig
new file mode 100644
index 000000000..c2d4411e8
--- /dev/null
+++ b/src/libuv/build.zig
@@ -0,0 +1,132 @@
+const std = @import("std");
+
+/// This is the type returned by create.
+pub const Library = struct {
+ step: *std.build.LibExeObjStep,
+
+ /// statically link this library into the given step
+ pub fn link(self: Library, other: *std.build.LibExeObjStep) void {
+ self.addIncludeDirs(other);
+ other.linkLibrary(self.step);
+ }
+
+ /// only add the include dirs to the given step. This is useful if building
+ /// a static library that you don't want to fully link in the code of this
+ /// library.
+ pub fn addIncludeDirs(self: Library, other: *std.build.LibExeObjStep) void {
+ _ = self;
+ other.addIncludeDir(include_dir);
+ }
+};
+
+/// Create this library. This is the primary API users of build.zig should
+/// use to link this library to their application. On the resulting Library,
+/// call the link function and given your own application step.
+pub fn create(
+ b: *std.build.Builder,
+ target: std.zig.CrossTarget,
+ mode: std.builtin.Mode,
+) !Library {
+ const ret = b.addStaticLibrary("uv", null);
+ ret.setTarget(target);
+ ret.setBuildMode(mode);
+
+ var flags = std.ArrayList([]const u8).init(b.allocator);
+ defer flags.deinit();
+
+ // try flags.appendSlice(&.{});
+
+ if (!target.isWindows()) {
+ try flags.appendSlice(&.{
+ "-D_FILE_OFFSET_BITS=64",
+ "-D_LARGEFILE_SOURCE",
+ });
+ }
+
+ if (target.isLinux()) {
+ try flags.appendSlice(&.{
+ "-D_GNU_SOURCE",
+ "-D_POSIX_C_SOURCE=200112",
+ });
+ }
+
+ // C files common to all platforms
+ ret.addCSourceFiles(&.{
+ root() ++ "src/fs-poll.c",
+ root() ++ "src/idna.c",
+ root() ++ "src/inet.c",
+ root() ++ "src/random.c",
+ root() ++ "src/strscpy.c",
+ root() ++ "src/strtok.c",
+ root() ++ "src/threadpool.c",
+ root() ++ "src/timer.c",
+ root() ++ "src/uv-common.c",
+ root() ++ "src/uv-data-getter-setters.c",
+ root() ++ "src/version.c",
+ }, flags.items);
+
+ if (!target.isWindows()) {
+ ret.addCSourceFiles(&.{
+ root() ++ "src/unix/async.c",
+ root() ++ "src/unix/core.c",
+ root() ++ "src/unix/dl.c",
+ root() ++ "src/unix/fs.c",
+ root() ++ "src/unix/getaddrinfo.c",
+ root() ++ "src/unix/getnameinfo.c",
+ root() ++ "src/unix/loop-watcher.c",
+ root() ++ "src/unix/loop.c",
+ root() ++ "src/unix/pipe.c",
+ root() ++ "src/unix/poll.c",
+ root() ++ "src/unix/process.c",
+ root() ++ "src/unix/random-devurandom.c",
+ root() ++ "src/unix/signal.c",
+ root() ++ "src/unix/stream.c",
+ root() ++ "src/unix/tcp.c",
+ root() ++ "src/unix/thread.c",
+ root() ++ "src/unix/tty.c",
+ root() ++ "src/unix/udp.c",
+ }, flags.items);
+ }
+
+ if (target.isLinux() or target.isDarwin()) {
+ ret.addCSourceFiles(&.{
+ root() ++ "src/unix/proctitle.c",
+ }, flags.items);
+ }
+
+ if (target.isLinux()) {
+ ret.addCSourceFiles(&.{
+ root() ++ "src/unix/linux-core.c",
+ root() ++ "src/unix/linux-inotify.c",
+ root() ++ "src/unix/linux-syscalls.c",
+ root() ++ "src/unix/procfs-exepath.c",
+ root() ++ "src/unix/random-getrandom.c",
+ root() ++ "src/unix/random-sysctl-linux.c",
+ root() ++ "src/unix/epoll.c",
+ }, flags.items);
+ }
+
+ ret.addIncludeDir(include_dir);
+ ret.addIncludeDir(root() ++ "src");
+ if (target.isWindows()) {
+ ret.linkSystemLibrary("psapi");
+ ret.linkSystemLibrary("user32");
+ ret.linkSystemLibrary("advapi32");
+ ret.linkSystemLibrary("iphlpapi");
+ ret.linkSystemLibrary("userenv");
+ ret.linkSystemLibrary("ws2_32");
+ }
+ if (target.isLinux()) {
+ ret.linkSystemLibrary("pthread");
+ }
+ ret.linkLibC();
+
+ return Library{ .step = ret };
+}
+
+fn root() []const u8 {
+ return (std.fs.path.dirname(@src().file) orelse unreachable) ++ "/../../vendor/libuv/";
+}
+
+/// Directories with our includes.
+const include_dir = root() ++ "include";
diff --git a/src/libuv/c.zig b/src/libuv/c.zig
new file mode 100644
index 000000000..b66f023bf
--- /dev/null
+++ b/src/libuv/c.zig
@@ -0,0 +1,3 @@
+pub usingnamespace @cImport({
+ @cInclude("uv.h");
+});
diff --git a/src/libuv/error.zig b/src/libuv/error.zig
new file mode 100644
index 000000000..1bab2d6fc
--- /dev/null
+++ b/src/libuv/error.zig
@@ -0,0 +1,185 @@
+const std = @import("std");
+const testing = std.testing;
+const c = @import("c.zig");
+
+/// Errors that libuv can produce
+///
+/// http://docs.libuv.org/en/v1.x/errors.html
+pub const Error = error{
+ E2BIG,
+ EACCES,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ EAFNOSUPPORT,
+ EAGAIN,
+ EAI_ADDRFAMILY,
+ EAI_AGAIN,
+ EAI_BADFLAGS,
+ EAI_BADHINTS,
+ EAI_CANCELED,
+ EAI_FAIL,
+ EAI_FAMILY,
+ EAI_MEMORY,
+ EAI_NODATA,
+ EAI_NONAME,
+ EAI_OVERFLOW,
+ EAI_PROTOCOL,
+ EAI_SERVICE,
+ EAI_SOCKTYPE,
+ EALREADY,
+ EBADF,
+ EBUSY,
+ ECANCELED,
+ ECHARSET,
+ ECONNABORTED,
+ ECONNREFUSED,
+ ECONNRESET,
+ EDESTADDRREQ,
+ EEXIST,
+ EFAULT,
+ EFBIG,
+ EHOSTUNREACH,
+ EINTR,
+ EINVAL,
+ EIO,
+ EISCONN,
+ EISDIR,
+ ELOOP,
+ EMFILE,
+ EMSGSIZE,
+ ENAMETOOLONG,
+ ENETDOWN,
+ ENETUNREACH,
+ ENFILE,
+ ENOBUFS,
+ ENODEV,
+ ENOENT,
+ ENOMEM,
+ ENONET,
+ ENOPROTOOPT,
+ ENOSPC,
+ ENOSYS,
+ ENOTCONN,
+ ENOTDIR,
+ ENOTEMPTY,
+ ENOTSOCK,
+ ENOTSUP,
+ EPERM,
+ EPIPE,
+ EPROTO,
+ EPROTONOSUPPORT,
+ EPROTOTYPE,
+ ERANGE,
+ EROFS,
+ ESHUTDOWN,
+ ESPIPE,
+ ESRCH,
+ ETIMEDOUT,
+ ETXTBSY,
+ EXDEV,
+ UNKNOWN,
+ EOF,
+ ENXIO,
+ EMLINK,
+ EHOSTDOWN,
+ EREMOTEIO,
+ ENOTTY,
+ EFTYPE,
+ EILSEQ,
+ ESOCKTNOSUPPORT,
+};
+
+/// Convert the result of a libuv API call to an error (or no error).
+pub fn convertError(r: i32) !void {
+ if (r >= 0) return;
+
+ return switch (r) {
+ c.UV_E2BIG => Error.E2BIG,
+ c.UV_EACCES => Error.EACCES,
+ c.UV_EADDRINUSE => Error.EADDRINUSE,
+ c.UV_EADDRNOTAVAIL => Error.EADDRNOTAVAIL,
+ c.UV_EAFNOSUPPORT => Error.EAFNOSUPPORT,
+ c.UV_EAGAIN => Error.EAGAIN,
+ c.UV_EAI_ADDRFAMILY => Error.EAI_ADDRFAMILY,
+ c.UV_EAI_AGAIN => Error.EAI_AGAIN,
+ c.UV_EAI_BADFLAGS => Error.EAI_BADFLAGS,
+ c.UV_EAI_BADHINTS => Error.EAI_BADHINTS,
+ c.UV_EAI_CANCELED => Error.EAI_CANCELED,
+ c.UV_EAI_FAIL => Error.EAI_FAIL,
+ c.UV_EAI_FAMILY => Error.EAI_FAMILY,
+ c.UV_EAI_MEMORY => Error.EAI_MEMORY,
+ c.UV_EAI_NODATA => Error.EAI_NODATA,
+ c.UV_EAI_NONAME => Error.EAI_NONAME,
+ c.UV_EAI_OVERFLOW => Error.EAI_OVERFLOW,
+ c.UV_EAI_PROTOCOL => Error.EAI_PROTOCOL,
+ c.UV_EAI_SERVICE => Error.EAI_SERVICE,
+ c.UV_EAI_SOCKTYPE => Error.EAI_SOCKTYPE,
+ c.UV_EALREADY => Error.EALREADY,
+ c.UV_EBADF => Error.EBADF,
+ c.UV_EBUSY => Error.EBUSY,
+ c.UV_ECANCELED => Error.ECANCELED,
+ c.UV_ECHARSET => Error.ECHARSET,
+ c.UV_ECONNABORTED => Error.ECONNABORTED,
+ c.UV_ECONNREFUSED => Error.ECONNREFUSED,
+ c.UV_ECONNRESET => Error.ECONNRESET,
+ c.UV_EDESTADDRREQ => Error.EDESTADDRREQ,
+ c.UV_EEXIST => Error.EEXIST,
+ c.UV_EFAULT => Error.EFAULT,
+ c.UV_EFBIG => Error.EFBIG,
+ c.UV_EHOSTUNREACH => Error.EHOSTUNREACH,
+ c.UV_EINTR => Error.EINTR,
+ c.UV_EINVAL => Error.EINVAL,
+ c.UV_EIO => Error.EIO,
+ c.UV_EISCONN => Error.EISCONN,
+ c.UV_EISDIR => Error.EISDIR,
+ c.UV_ELOOP => Error.ELOOP,
+ c.UV_EMFILE => Error.EMFILE,
+ c.UV_EMSGSIZE => Error.EMSGSIZE,
+ c.UV_ENAMETOOLONG => Error.ENAMETOOLONG,
+ c.UV_ENETDOWN => Error.ENETDOWN,
+ c.UV_ENETUNREACH => Error.ENETUNREACH,
+ c.UV_ENFILE => Error.ENFILE,
+ c.UV_ENOBUFS => Error.ENOBUFS,
+ c.UV_ENODEV => Error.ENODEV,
+ c.UV_ENOENT => Error.ENOENT,
+ c.UV_ENOMEM => Error.ENOMEM,
+ c.UV_ENONET => Error.ENONET,
+ c.UV_ENOPROTOOPT => Error.ENOPROTOOPT,
+ c.UV_ENOSPC => Error.ENOSPC,
+ c.UV_ENOSYS => Error.ENOSYS,
+ c.UV_ENOTCONN => Error.ENOTCONN,
+ c.UV_ENOTDIR => Error.ENOTDIR,
+ c.UV_ENOTEMPTY => Error.ENOTEMPTY,
+ c.UV_ENOTSOCK => Error.ENOTSOCK,
+ c.UV_ENOTSUP => Error.ENOTSUP,
+ c.UV_EPERM => Error.EPERM,
+ c.UV_EPIPE => Error.EPIPE,
+ c.UV_EPROTO => Error.EPROTO,
+ c.UV_EPROTONOSUPPORT => Error.EPROTONOSUPPORT,
+ c.UV_EPROTOTYPE => Error.EPROTOTYPE,
+ c.UV_ERANGE => Error.ERANGE,
+ c.UV_EROFS => Error.EROFS,
+ c.UV_ESHUTDOWN => Error.ESHUTDOWN,
+ c.UV_ESPIPE => Error.ESPIPE,
+ c.UV_ESRCH => Error.ESRCH,
+ c.UV_ETIMEDOUT => Error.ETIMEDOUT,
+ c.UV_ETXTBSY => Error.ETXTBSY,
+ c.UV_EXDEV => Error.EXDEV,
+ c.UV_UNKNOWN => Error.UNKNOWN,
+ c.UV_EOF => Error.EOF,
+ c.UV_ENXIO => Error.ENXIO,
+ c.UV_EHOSTDOWN => Error.EHOSTDOWN,
+ c.UV_EREMOTEIO => Error.EREMOTEIO,
+ c.UV_ENOTTY => Error.ENOTTY,
+ c.UV_EFTYPE => Error.EFTYPE,
+ c.UV_EILSEQ => Error.EILSEQ,
+ c.UV_ESOCKTNOSUPPORT => Error.ESOCKTNOSUPPORT,
+ else => unreachable,
+ };
+}
+
+test {
+ // This is mostly just forcing our error type and function to be
+ // codegenned and run once to ensure we have all the types.
+ try testing.expectError(Error.EFTYPE, convertError(c.UV_EFTYPE));
+}
diff --git a/src/libuv/main.zig b/src/libuv/main.zig
new file mode 100644
index 000000000..d012ab5d3
--- /dev/null
+++ b/src/libuv/main.zig
@@ -0,0 +1,7 @@
+const Loop = @import("Loop.zig");
+const Error = @import("error.zig").Error;
+
+test {
+ _ = Loop;
+ _ = Error;
+}
diff --git a/src/main.zig b/src/main.zig
index c7f947619..36c492f2e 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -26,4 +26,7 @@ test {
_ = @import("Command.zig");
_ = @import("TempDir.zig");
_ = @import("terminal/Terminal.zig");
+
+ // TEMP
+ _ = @import("libuv/main.zig");
}
diff --git a/vendor/libuv b/vendor/libuv
new file mode 160000
+Subproject 9e59aa1bc8c4d215ea3e05eafec7181747206f6