Commit be6a81d3a7

Andrew Kelley <andrew@ziglang.org>
2023-01-03 06:57:25
Merge pull request #13699 from mikdusan/bsd
give BSDs some attention
1 parent 5572a83
lib/libcxx/include/__config
@@ -148,7 +148,7 @@
 #    endif
 // Feature macros for disabling pre ABI v1 features. All of these options
 // are deprecated.
-#    if defined(__FreeBSD__)
+#    if defined(__FreeBSD__) || defined(__DragonFly__)
 #      define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR
 #    endif
 #  endif
@@ -726,11 +726,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
 #  endif // _LIBCPP_CXX03_LANG
 
 #  if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || defined(__sun__) ||                \
-      defined(__NetBSD__)
+      defined(__NetBSD__) || defined(__DragonFly__)
 #    define _LIBCPP_LOCALE__L_EXTENSIONS 1
 #  endif
 
-#  ifdef __FreeBSD__
+#  if defined(__FreeBSD__) || defined(__DragonFly__)
 #    define _DECLARE_C99_LDBL_MATH 1
 #  endif
 
@@ -750,11 +750,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
 #    define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
 #  endif
 
-#  if defined(__APPLE__) || defined(__FreeBSD__)
+#  if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
 #    define _LIBCPP_HAS_DEFAULTRUNELOCALE
 #  endif
 
-#  if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__)
+#  if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__) || defined(__DragonFly__)
 #    define _LIBCPP_WCTYPE_IS_MASK
 #  endif
 
@@ -901,6 +901,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
 
 #    if defined(__FreeBSD__) ||                                                                                        \
         defined(__wasi__) ||                                                                                           \
+        defined(__DragonFly__) ||                                                                                      \
         defined(__NetBSD__) ||                                                                                         \
         defined(__OpenBSD__) ||                                                                                        \
         defined(__NuttX__) ||                                                                                          \
lib/libcxx/include/__locale
@@ -33,7 +33,7 @@
 # include <__support/newlib/xlocale.h>
 #elif defined(__OpenBSD__)
 # include <__support/openbsd/xlocale.h>
-#elif (defined(__APPLE__) || defined(__FreeBSD__))
+#elif (defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__))
 # include <xlocale.h>
 #elif defined(__Fuchsia__)
 # include <__support/fuchsia/xlocale.h>
@@ -453,10 +453,10 @@ public:
     static const mask __regex_word = 0x4000; // 0x8000 and 0x0100 and 0x00ff are used
 # define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
 # define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
-#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__)
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__DragonFly__)
 # ifdef __APPLE__
     typedef __uint32_t mask;
-# elif defined(__FreeBSD__)
+# elif defined(__FreeBSD__) || defined(__DragonFly__)
     typedef unsigned long mask;
 # elif defined(__EMSCRIPTEN__) || defined(__NetBSD__)
     typedef unsigned short mask;
lib/libcxx/include/locale
@@ -239,7 +239,7 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if defined(__APPLE__) || defined(__FreeBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
 #  define _LIBCPP_GET_C_LOCALE 0
 #elif defined(__NetBSD__)
 #  define _LIBCPP_GET_C_LOCALE LC_C_LOCALE
lib/libcxx/src/locale.cpp
@@ -1190,7 +1190,7 @@ ctype<char>::classic_table() noexcept
 const ctype<char>::mask*
 ctype<char>::classic_table() noexcept
 {
-#if defined(__APPLE__) || defined(__FreeBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
     return _DefaultRuneLocale.__runetype;
 #elif defined(__NetBSD__)
     return _C_ctype_tab_ + 1;
lib/std/c/dragonfly.zig
@@ -12,6 +12,7 @@ pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
 pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
 pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
 pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
+pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
 
 pub const dl_iterate_phdr_callback = std.meta.FnPtr(fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int);
 pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int;
@@ -419,6 +420,7 @@ pub const F = struct {
     pub const DUP2FD = 10;
     pub const DUPFD_CLOEXEC = 17;
     pub const DUP2FD_CLOEXEC = 18;
+    pub const GETPATH = 19;
 };
 
 pub const FD_CLOEXEC = 1;
lib/std/c/freebsd.zig
@@ -15,12 +15,15 @@ pub extern "c" fn pthread_getthreadid_np() c_int;
 pub extern "c" fn pthread_set_name_np(thread: std.c.pthread_t, name: [*:0]const u8) void;
 pub extern "c" fn pthread_get_name_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) void;
 pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
+pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
 
 pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
 pub extern "c" fn malloc_usable_size(?*const anyopaque) usize;
 
 pub extern "c" fn getpid() pid_t;
 
+pub extern "c" fn kinfo_getfile(pid: pid_t, cntp: *c_int) ?[*]kinfo_file;
+
 pub const sf_hdtr = extern struct {
     headers: [*]const iovec_const,
     hdr_cnt: c_int,
lib/std/c/netbsd.zig
@@ -537,6 +537,7 @@ pub const KERN = struct {
 };
 
 pub const PATH_MAX = 1024;
+pub const NAME_MAX = 255;
 pub const IOV_MAX = KERN.IOV_MAX;
 
 pub const STDIN_FILENO = 0;
@@ -689,13 +690,17 @@ pub const F = struct {
     pub const SETFD = 2;
     pub const GETFL = 3;
     pub const SETFL = 4;
-
     pub const GETOWN = 5;
     pub const SETOWN = 6;
-
     pub const GETLK = 7;
     pub const SETLK = 8;
     pub const SETLKW = 9;
+    pub const CLOSEM = 10;
+    pub const MAXFD = 11;
+    pub const DUPFD_CLOEXEC = 12;
+    pub const GETNOSIGPIPE = 13;
+    pub const SETNOSIGPIPE = 14;
+    pub const GETPATH = 15;
 
     pub const RDLCK = 1;
     pub const WRLCK = 3;
lib/std/c/openbsd.zig
@@ -417,6 +417,7 @@ pub const AI = struct {
 };
 
 pub const PATH_MAX = 1024;
+pub const NAME_MAX = 255;
 pub const IOV_MAX = 1024;
 
 pub const STDIN_FILENO = 0;
lib/std/fs/test.zig
@@ -451,8 +451,8 @@ test "file operations on directories" {
     try testing.expectError(error.IsDir, tmp_dir.dir.createFile(test_dir_name, .{}));
     try testing.expectError(error.IsDir, tmp_dir.dir.deleteFile(test_dir_name));
     switch (builtin.os.tag) {
-        // NetBSD does not error when reading a directory.
-        .netbsd => {},
+        // no error when reading a directory.
+        .dragonfly, .netbsd => {},
         // Currently, WASI will return error.Unexpected (via ENOTCAPABLE) when attempting fd_read on a directory handle.
         // TODO: Re-enable on WASI once https://github.com/bytecodealliance/wasmtime/issues/1935 is resolved.
         .wasi => {},
lib/std/os/test.zig
@@ -523,7 +523,14 @@ test "argsAlloc" {
 
 test "memfd_create" {
     // memfd_create is only supported by linux and freebsd.
-    if (native_os != .linux and native_os != .freebsd) return error.SkipZigTest;
+    switch (native_os) {
+        .linux => {},
+        .freebsd => {
+            if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .lt)
+                return error.SkipZigTest;
+        },
+        else => return error.SkipZigTest,
+    }
 
     const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {
         // Related: https://github.com/ziglang/zig/issues/4019
lib/std/fs.zig
@@ -34,7 +34,7 @@ pub const Watch = @import("fs/watch.zig").Watch;
 /// fit into a UTF-8 encoded array of this length.
 /// The byte count includes room for a null sentinel byte.
 pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
-    .linux, .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .haiku, .solaris => os.PATH_MAX,
+    .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris => os.PATH_MAX,
     // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
     // If it would require 4 UTF-8 bytes, then there would be a surrogate
     // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
@@ -54,10 +54,10 @@ pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
 /// (depending on the platform) this assumption may not hold for every configuration.
 /// The byte count does not include a null sentinel byte.
 pub const MAX_NAME_BYTES = switch (builtin.os.tag) {
-    .linux, .macos, .ios, .freebsd, .dragonfly => os.NAME_MAX,
+    .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly => os.NAME_MAX,
     // Haiku's NAME_MAX includes the null terminator, so subtract one.
     .haiku => os.NAME_MAX - 1,
-    .netbsd, .openbsd, .solaris => os.MAXNAMLEN,
+    .solaris => os.system.MAXNAMLEN,
     // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
     // If it would require 4 UTF-8 bytes, then there would be a surrogate
     // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
lib/std/os.zig
@@ -2818,6 +2818,8 @@ pub fn mkdiratZ(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirErr
         .NOSPC => return error.NoSpaceLeft,
         .NOTDIR => return error.NotDir,
         .ROFS => return error.ReadOnlyFileSystem,
+        // dragonfly: when dir_fd is unlinked from filesystem
+        .NOTCONN => return error.FileNotFound,
         else => |err| return unexpectedErrno(err),
     }
 }
@@ -5258,6 +5260,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
             switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {
                 .SUCCESS => {},
                 .BADF => return error.FileNotFound,
+                .NOSPC => return error.NameTooLong,
                 // TODO man pages for fcntl on macOS don't really tell you what
                 // errno values to expect when command is F.GETPATH...
                 else => |err| return unexpectedErrno(err),
@@ -5290,19 +5293,85 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
             return target;
         },
         .freebsd => {
-            comptime if (builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .lt)
-                @compileError("querying for canonical path of a handle is unsupported on FreeBSD 12 and below");
-
-            var kfile: system.kinfo_file = undefined;
-            kfile.structsize = system.KINFO_FILE_SIZE;
-            switch (errno(system.fcntl(fd, system.F.KINFO, @ptrToInt(&kfile)))) {
+            if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .gt) {
+                var kfile: system.kinfo_file = undefined;
+                kfile.structsize = system.KINFO_FILE_SIZE;
+                switch (errno(system.fcntl(fd, system.F.KINFO, @ptrToInt(&kfile)))) {
+                    .SUCCESS => {},
+                    .BADF => return error.FileNotFound,
+                    else => |err| return unexpectedErrno(err),
+                }
+                const len = mem.indexOfScalar(u8, &kfile.path, 0) orelse MAX_PATH_BYTES;
+                if (len == 0) return error.NameTooLong;
+                mem.copy(u8, out_buffer, kfile.path[0..len]);
+                return out_buffer[0..len];
+            } else {
+                // This fallback implementation reimplements libutil's `kinfo_getfile()`.
+                // The motivation is to avoid linking -lutil when building zig or general
+                // user executables.
+                var mib = [4]c_int{ CTL.KERN, KERN.PROC, KERN.PROC_FILEDESC, system.getpid() };
+                var len: usize = undefined;
+                sysctl(&mib, null, &len, null, 0) catch |err| switch (err) {
+                    error.PermissionDenied => unreachable,
+                    error.SystemResources => return error.SystemResources,
+                    error.NameTooLong => unreachable,
+                    error.UnknownName => unreachable,
+                    else => return error.Unexpected,
+                };
+                len = len * 4 / 3;
+                const buf = std.heap.c_allocator.alloc(u8, len) catch return error.SystemResources;
+                defer std.heap.c_allocator.free(buf);
+                len = buf.len;
+                sysctl(&mib, &buf[0], &len, null, 0) catch |err| switch (err) {
+                    error.PermissionDenied => unreachable,
+                    error.SystemResources => return error.SystemResources,
+                    error.NameTooLong => unreachable,
+                    error.UnknownName => unreachable,
+                    else => return error.Unexpected,
+                };
+                var i: usize = 0;
+                while (i < len) {
+                    const kf: *align(1) system.kinfo_file = @ptrCast(*align(1) system.kinfo_file, &buf[i]);
+                    if (kf.fd == fd) {
+                        len = mem.indexOfScalar(u8, &kf.path, 0) orelse MAX_PATH_BYTES;
+                        if (len == 0) return error.NameTooLong;
+                        mem.copy(u8, out_buffer, kf.path[0..len]);
+                        return out_buffer[0..len];
+                    }
+                    i += @intCast(usize, kf.structsize);
+                }
+                return error.InvalidHandle;
+            }
+        },
+        .dragonfly => {
+            if (comptime builtin.os.version_range.semver.max.order(.{ .major = 6, .minor = 0 }) == .lt) {
+                @compileError("querying for canonical path of a handle is unsupported on this host");
+            }
+            @memset(out_buffer, 0, MAX_PATH_BYTES);
+            switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {
                 .SUCCESS => {},
                 .BADF => return error.FileNotFound,
+                .RANGE => return error.NameTooLong,
                 else => |err| return unexpectedErrno(err),
             }
-
-            const len = mem.indexOfScalar(u8, &kfile.path, 0) orelse MAX_PATH_BYTES;
-            mem.copy(u8, out_buffer, kfile.path[0..len]);
+            const len = mem.indexOfScalar(u8, out_buffer[0..], @as(u8, 0)) orelse MAX_PATH_BYTES;
+            return out_buffer[0..len];
+        },
+        .netbsd => {
+            if (comptime builtin.os.version_range.semver.max.order(.{ .major = 10, .minor = 0 }) == .lt) {
+                @compileError("querying for canonical path of a handle is unsupported on this host");
+            }
+            @memset(out_buffer, 0, MAX_PATH_BYTES);
+            switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {
+                .SUCCESS => {},
+                .ACCES => return error.AccessDenied,
+                .BADF => return error.FileNotFound,
+                .NOENT => return error.FileNotFound,
+                .NOMEM => return error.SystemResources,
+                .RANGE => return error.NameTooLong,
+                else => |err| return unexpectedErrno(err),
+            }
+            const len = mem.indexOfScalar(u8, out_buffer[0..], @as(u8, 0)) orelse MAX_PATH_BYTES;
             return out_buffer[0..len];
         },
         else => @compileError("querying for canonical path of a handle is unsupported on this host"),
@@ -6675,6 +6744,8 @@ pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
             }
         },
         .freebsd => {
+            if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .lt)
+                @compileError("memfd_create is unavailable on FreeBSD < 13.0");
             const rc = system.memfd_create(name, flags);
             switch (errno(rc)) {
                 .SUCCESS => return rc,
lib/std/target.zig
@@ -271,7 +271,7 @@ pub const Target = struct {
                     .freebsd => return .{
                         .semver = Version.Range{
                             .min = .{ .major = 12, .minor = 0 },
-                            .max = .{ .major = 13, .minor = 0 },
+                            .max = .{ .major = 13, .minor = 1 },
                         },
                     },
                     .macos => return switch (arch) {
@@ -310,19 +310,19 @@ pub const Target = struct {
                     .netbsd => return .{
                         .semver = .{
                             .min = .{ .major = 8, .minor = 0 },
-                            .max = .{ .major = 9, .minor = 1 },
+                            .max = .{ .major = 10, .minor = 0 },
                         },
                     },
                     .openbsd => return .{
                         .semver = .{
                             .min = .{ .major = 6, .minor = 8 },
-                            .max = .{ .major = 6, .minor = 9 },
+                            .max = .{ .major = 7, .minor = 2 },
                         },
                     },
                     .dragonfly => return .{
                         .semver = .{
                             .min = .{ .major = 5, .minor = 8 },
-                            .max = .{ .major = 6, .minor = 0 },
+                            .max = .{ .major = 6, .minor = 4 },
                         },
                     },
                     .solaris => return .{
src/link/Elf.zig
@@ -3074,27 +3074,22 @@ const CsuObjects = struct {
 
         var result: CsuObjects = .{};
 
-        // TODO: https://github.com/ziglang/zig/issues/4629
-        // - use inline enum type
-        // - reduce to enum-literals for values
-        const Mode = enum {
+        // Flatten crt cases.
+        const mode: enum {
             dynamic_lib,
             dynamic_exe,
             dynamic_pie,
             static_exe,
             static_pie,
-        };
-
-        // Flatten crt case types.
-        const mode: Mode = switch (link_options.output_mode) {
+        } = switch (link_options.output_mode) {
             .Obj => return CsuObjects{},
             .Lib => switch (link_options.link_mode) {
-                .Dynamic => Mode.dynamic_lib,
+                .Dynamic => .dynamic_lib,
                 .Static => return CsuObjects{},
             },
             .Exe => switch (link_options.link_mode) {
-                .Dynamic => if (link_options.pie) Mode.dynamic_pie else Mode.dynamic_exe,
-                .Static => if (link_options.pie) Mode.static_pie else Mode.static_exe,
+                .Dynamic => if (link_options.pie) .dynamic_pie else .dynamic_exe,
+                .Static => if (link_options.pie) .static_pie else .static_exe,
             },
         };
 
@@ -3124,7 +3119,6 @@ const CsuObjects = struct {
                         // hosted-glibc provides crtbegin/end objects in platform/compiler-specific dirs
                         // and they are not known at comptime. For now null-out crtbegin/end objects;
                         // there is no feature loss, zig has never linked those objects in before.
-                        // TODO: probe for paths, ie. `cc -print-file-name`
                         result.crtbegin = null;
                         result.crtend = null;
                     } else {
build.zig
@@ -593,24 +593,38 @@ fn addCmakeCfgOptionsToExe(
 
         // System -lc++ must be used because in this code path we are attempting to link
         // against system-provided LLVM, Clang, LLD.
-        if (exe.target.getOsTag() == .linux) {
-            // First we try to link against gcc libstdc++. If that doesn't work, we fall
-            // back to -lc++ and cross our fingers.
-            addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), "", need_cpp_includes) catch |err| switch (err) {
-                error.RequiredLibraryNotFound => {
-                    exe.linkSystemLibrary("c++");
-                },
-                else => |e| return e,
-            };
-            exe.linkSystemLibrary("unwind");
-        } else if (exe.target.isFreeBSD()) {
-            try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
-            exe.linkSystemLibrary("pthread");
-        } else if (exe.target.getOsTag() == .openbsd) {
-            try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
-            try addCxxKnownPath(b, cfg, exe, b.fmt("libc++abi.{s}", .{lib_suffix}), null, need_cpp_includes);
-        } else if (exe.target.isDarwin()) {
-            exe.linkSystemLibrary("c++");
+        switch (exe.target.getOsTag()) {
+            .linux => {
+                // First we try to link against gcc libstdc++. If that doesn't work, we fall
+                // back to -lc++ and cross our fingers.
+                addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), "", need_cpp_includes) catch |err| switch (err) {
+                    error.RequiredLibraryNotFound => {
+                        exe.linkSystemLibrary("c++");
+                    },
+                    else => |e| return e,
+                };
+                exe.linkSystemLibrary("unwind");
+            },
+            .ios, .macos, .watchos, .tvos => {
+                exe.linkSystemLibrary("c++");
+            },
+            .freebsd => {
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
+            },
+            .openbsd => {
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libc++abi.{s}", .{lib_suffix}), null, need_cpp_includes);
+            },
+            .netbsd => {
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
+            },
+            .dragonfly => {
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
+                try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
+            },
+            else => {},
         }
     }