From a2e881ff4ef83792500bb4b985bb70063bb58ea8 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Thu, 14 Sep 2023 02:34:43 -0600 Subject: [PATCH] windows: initial support for zig build test Makes progress getting "zig build test" to work on windows. Mostly fixed issues around build configuration and added some branches throughout the Zig code to return/throw errors for unimplemented parts. I also added an initial implementation for getting the home dir. --- build.zig | 10 +++++++--- pkg/fontconfig/build.zig | 33 ++++++++++++++++++++------------- pkg/freetype/build.zig | 1 - pkg/harfbuzz/build.zig | 14 +++++++++----- pkg/utf8proc/build.zig | 1 + src/Command.zig | 13 ++++++++++++- src/Pty.zig | 6 ++++++ src/os/homedir.zig | 31 +++++++++++++++++++++++++++++++ src/os/passwd.zig | 4 +++- 9 files changed, 89 insertions(+), 24 deletions(-) diff --git a/build.zig b/build.zig index 231595afb..7d667db0d 100644 --- a/build.zig +++ b/build.zig @@ -329,7 +329,7 @@ pub fn build(b: *std.Build) !void { // Convert to termcap source format if thats helpful to people and // install it. The resulting value here is the termcap source in case // that is used for other commands. - { + if (!target.isWindows()) { const run_step = RunStep.create(b, "infotocap"); run_step.addArg("infotocap"); run_step.addFileSourceArg(src_source); @@ -349,7 +349,7 @@ pub fn build(b: *std.Build) !void { } // Compile the terminfo source into a terminfo database - { + if (!target.isWindows()) { const run_step = RunStep.create(b, "tic"); run_step.addArgs(&.{ "tic", "-x", "-o" }); const path = run_step.addOutputFileArg("terminfo"); @@ -799,7 +799,11 @@ fn addDeps( b, step.target, step.optimize, - .{ .lzma = false, .zlib = false }, + .{ + .lzma = false, + .zlib = false, + .iconv = !step.target.isWindows(), + }, ); libxml2_lib.link(step); diff --git a/pkg/fontconfig/build.zig b/pkg/fontconfig/build.zig index 5f09408e2..b319cf45f 100644 --- a/pkg/fontconfig/build.zig +++ b/pkg/fontconfig/build.zig @@ -99,15 +99,9 @@ pub fn buildFontconfig( "-DHAVE_STDLIB_H", "-DHAVE_STRING_H", "-DHAVE_UNISTD_H", - "-DHAVE_SYS_STATVFS_H", - "-DHAVE_SYS_VFS_H", - "-DHAVE_SYS_STATFS_H", "-DHAVE_SYS_PARAM_H", - "-DHAVE_SYS_MOUNT_H", - "-DHAVE_LINK", "-DHAVE_MKSTEMP", - "-DHAVE_MKOSTEMP", "-DHAVE__MKTEMP_S", "-DHAVE_MKDTEMP", "-DHAVE_GETOPT", @@ -115,15 +109,9 @@ pub fn buildFontconfig( //"-DHAVE_GETPROGNAME", //"-DHAVE_GETEXECNAME", "-DHAVE_RAND", - "-DHAVE_RANDOM", - "-DHAVE_LRAND48", //"-DHAVE_RANDOM_R", - "-DHAVE_RAND_R", - "-DHAVE_READLINK", "-DHAVE_FSTATVFS", "-DHAVE_FSTATFS", - "-DHAVE_LSTAT", - "-DHAVE_MMAP", "-DHAVE_VPRINTF", "-DHAVE_FT_GET_BDF_PROPERTY", @@ -175,8 +163,27 @@ pub fn buildFontconfig( }); } - if (!target.isWindows()) { + if (target.isWindows()) { try flags.appendSlice(&.{ + "-DFC_CACHEDIR=\"LOCAL_APPDATA_FONTCONFIG_CACHE\"", + "-DFC_TEMPLATEDIR=\"c:/share/fontconfig/conf.avail\"", + "-DCONFIGDIR=\"c:/etc/fonts/conf.d\"", + "-DFC_DEFAULT_FONTS=\"\\tWINDOWSFONTDIR\\n\\tWINDOWSUSERFONTDIR\\n\"", + }); + } else { + try flags.appendSlice(&.{ + "-DHAVE_SYS_STATVFS_H", + "-DHAVE_SYS_VFS_H", + "-DHAVE_SYS_STATFS_H", + "-DHAVE_SYS_MOUNT_H", + "-DHAVE_LINK", + "-DHAVE_MKOSTEMP", + "-DHAVE_RANDOM", + "-DHAVE_LRAND48", + "-DHAVE_RAND_R", + "-DHAVE_READLINK", + "-DHAVE_LSTAT", + "-DHAVE_MMAP", "-DHAVE_PTHREAD", "-DFC_CACHEDIR=\"/var/cache/fontconfig\"", diff --git a/pkg/freetype/build.zig b/pkg/freetype/build.zig index add99b6ff..89534f10c 100644 --- a/pkg/freetype/build.zig +++ b/pkg/freetype/build.zig @@ -117,7 +117,6 @@ pub fn buildFreetype( .windows => { lib.addCSourceFiles(&.{ root ++ "builds/windows/ftdebug.c", - root ++ "src/base/ftver.c", }, flags.items); }, else => lib.addCSourceFile(.{ diff --git a/pkg/harfbuzz/build.zig b/pkg/harfbuzz/build.zig index 6d51156e5..1135ca322 100644 --- a/pkg/harfbuzz/build.zig +++ b/pkg/harfbuzz/build.zig @@ -81,13 +81,17 @@ pub fn buildHarfbuzz( defer flags.deinit(); try flags.appendSlice(&.{ - "-DHAVE_UNISTD_H", - "-DHAVE_SYS_MMAN_H", "-DHAVE_STDBOOL_H", - - // We always have pthread - "-DHAVE_PTHREAD=1", }); + + if (!step.target.isWindows()) { + try flags.appendSlice(&.{ + "-DHAVE_UNISTD_H", + "-DHAVE_SYS_MMAN_H", + "-DHAVE_PTHREAD=1", + }); + } + if (opt.freetype.enabled) try flags.appendSlice(&.{ "-DHAVE_FREETYPE=1", diff --git a/pkg/utf8proc/build.zig b/pkg/utf8proc/build.zig index 675c79630..7152766d6 100644 --- a/pkg/utf8proc/build.zig +++ b/pkg/utf8proc/build.zig @@ -41,6 +41,7 @@ pub fn buildLib( // Compile var flags = std.ArrayList([]const u8).init(b.allocator); + try flags.append("-DUTF8PROC_EXPORTS"); defer flags.deinit(); // C files diff --git a/src/Command.zig b/src/Command.zig index 8fa8808a5..5daa2bcfe 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -122,6 +122,9 @@ pub fn start(self: *Command, alloc: Allocator) !void { else @compileError("missing env vars"); + if (builtin.os.tag == .windows) + @panic("start not implemented on windows"); + // Fork const pid = try std.os.fork(); if (pid != 0) { @@ -187,6 +190,9 @@ fn setupFd(src: File.Handle, target: i32) !void { /// Wait for the command to exit and return information about how it exited. pub fn wait(self: Command, block: bool) !Exit { + if (builtin.os.tag == .windows) + @panic("wait not implemented on windows"); + const res = if (block) std.os.waitpid(self.pid.?, 0) else res: { // We specify NOHANG because its not our fault if the process we launch // for the tty doesn't properly waitpid its children. We don't want @@ -255,7 +261,7 @@ pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 { }; defer f.close(); const stat = try f.stat(); - if (stat.kind != .directory and stat.mode & 0o0111 != 0) { + if (stat.kind != .directory and isExecutable(stat.mode)) { return try alloc.dupe(u8, full_path); } } @@ -265,6 +271,11 @@ pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 { return null; } +fn isExecutable(mode: std.fs.File.Mode) bool { + if (builtin.os.tag == .windows) return true; + return mode & 0o0111 != 0; +} + test "expandPath: env" { const path = (try expandPath(testing.allocator, "env")).?; defer testing.allocator.free(path); diff --git a/src/Pty.zig b/src/Pty.zig index b8db3ee7c..7813e8880 100644 --- a/src/Pty.zig +++ b/src/Pty.zig @@ -13,6 +13,7 @@ const c = switch (builtin.os.tag) { @cInclude("sys/ioctl.h"); // ioctl and constants @cInclude("util.h"); // openpty() }), + .windows => { }, else => @cImport({ @cInclude("sys/ioctl.h"); // ioctl and constants @cInclude("pty.h"); @@ -45,6 +46,8 @@ slave: fd_t, /// Open a new PTY with the given initial size. pub fn open(size: winsize) !Pty { + if (builtin.os.tag == .windows) return error.NotImplementedOnWindows; + // Need to copy so that it becomes non-const. var sizeCopy = size; @@ -86,6 +89,8 @@ pub fn deinit(self: *Pty) void { /// Return the size of the pty. pub fn getSize(self: Pty) !winsize { + if (builtin.os.tag == .windows) return error.NotImplementedOnWindows; + var ws: winsize = undefined; if (c.ioctl(self.master, TIOCGWINSZ, @intFromPtr(&ws)) < 0) return error.IoctlFailed; @@ -95,6 +100,7 @@ pub fn getSize(self: Pty) !winsize { /// Set the size of the pty. pub fn setSize(self: Pty, size: winsize) !void { + if (builtin.os.tag == .windows) return error.NotImplementedOnWindows; if (c.ioctl(self.master, TIOCSWINSZ, @intFromPtr(&size)) < 0) return error.IoctlFailed; } diff --git a/src/os/homedir.zig b/src/os/homedir.zig index c16ff9489..d73405c09 100644 --- a/src/os/homedir.zig +++ b/src/os/homedir.zig @@ -13,6 +13,7 @@ const Error = error{ pub inline fn home(buf: []u8) !?[]u8 { return switch (builtin.os.tag) { inline .linux, .macos => try homeUnix(buf), + .windows => try homeWindows(buf), else => @compileError("unimplemented"), }; } @@ -77,6 +78,36 @@ fn homeUnix(buf: []u8) !?[]u8 { return null; } +fn homeWindows(buf: []u8) !?[]u8 { + const drive_len = blk: { + var fba_instance = std.heap.FixedBufferAllocator.init(buf); + const fba = fba_instance.allocator(); + const drive = std.process.getEnvVarOwned(fba, "HOMEDRIVE") catch |err| switch (err) { + error.OutOfMemory => return Error.BufferTooSmall, + error.InvalidUtf8, + error.EnvironmentVariableNotFound => return null, + }; + // could shift the contents if this ever happens + if (drive.ptr != buf.ptr) @panic("codebug"); + break :blk drive.len; + }; + + const path_len = blk: { + const path_buf = buf[drive_len..]; + var fba_instance = std.heap.FixedBufferAllocator.init(buf[drive_len..]); + const fba = fba_instance.allocator(); + const homepath = std.process.getEnvVarOwned(fba, "HOMEPATH") catch |err| switch (err) { + error.OutOfMemory => return Error.BufferTooSmall, + error.InvalidUtf8, + error.EnvironmentVariableNotFound => return null, + }; + // could shift the contents if this ever happens + if (homepath.ptr != path_buf.ptr) @panic("codebug"); + break :blk homepath.len; + }; + return buf[0 .. drive_len + path_len]; +} + fn trimSpace(input: []const u8) []const u8 { return std.mem.trim(u8, input, " \n\t"); } diff --git a/src/os/passwd.zig b/src/os/passwd.zig index 3b6a1eab7..8b5a9671c 100644 --- a/src/os/passwd.zig +++ b/src/os/passwd.zig @@ -15,7 +15,7 @@ comptime { } /// Used to determine the default shell and directory on Unixes. -const c = @cImport({ +const c = if (builtin.os.tag == .windows) { } else @cImport({ @cInclude("sys/types.h"); @cInclude("unistd.h"); @cInclude("pwd.h"); @@ -30,6 +30,8 @@ pub const Entry = struct { /// Get the passwd entry for the currently executing user. pub fn get(alloc: Allocator) !Entry { + if (builtin.os.tag == .windows) @panic("todo: windows"); + var buf: [1024]u8 = undefined; var pw: c.struct_passwd = undefined; var pw_ptr: ?*c.struct_passwd = null;