summaryrefslogtreecommitdiff
path: root/Ports/zig
diff options
context:
space:
mode:
authorsin-ack <sin-ack@users.noreply.github.com>2022-09-25 11:19:54 +0000
committerAndrew Kaster <andrewdkaster@gmail.com>2022-12-11 19:55:37 -0700
commitcda5a530e63872ee8700c518f51a4ea5dfba8604 (patch)
tree2a2eb6c7dc060d7c40e066534e012aef700cd419 /Ports/zig
parent27da878bb793d4f4eae2032a9a2a8acb036a22e1 (diff)
downloadserenity-cda5a530e63872ee8700c518f51a4ea5dfba8604.zip
Ports: Add zig port :^)
:yakkie: The build process for the Zig compiler is more involved than most of the other ports, because the Zig compiler is mostly self-hosting. In order to build it, the zig-bootstrap build system is used, which does the following: 1) Build LLVM for the host OS; 2) Build Zig for the host OS with the SerenityOS target enabled; 3) Build zlib, zstd and LLVM for SerenityOS using `zig cc` as the C/C++ compiler; 4) Build Zig for SerenityOS using the host Zig. A few hacks are required in order to tell `zig cc` and zig about what Serenity's libc looks like in the build process, but other than that it's fairly straightforward. All of the patches that are included with this commit are Zig-upstream ready once the LLVM patches are upstreamed.
Diffstat (limited to 'Ports/zig')
-rw-r--r--Ports/zig/.gitignore1
-rwxr-xr-xPorts/zig/package.sh27
l---------Ports/zig/patches/0001-Add-support-for-building-LLVM-on-SerenityOS.patch1
l---------Ports/zig/patches/0002-Add-triple-for-SerenityOS.patch1
l---------Ports/zig/patches/0003-Add-support-for-SerenityOS.patch1
l---------Ports/zig/patches/0004-Default-to-ftls-model-initial-exec-on-SerenityOS.patch1
-rw-r--r--Ports/zig/patches/0005-Add-support-for-SerenityOS.patch121
l---------Ports/zig/patches/0006-Allow-undefined-symbols-on-SerenityOS.patch1
l---------Ports/zig/patches/0007-Support-building-shared-libLLVM-and-libClang-for-Ser.patch1
l---------Ports/zig/patches/0008-Add-SerenityOS-to-config.guess.patch1
l---------Ports/zig/patches/0009-Prevent-the-use-of-POSIX-shm-on-SerenityOS.patch1
-rw-r--r--Ports/zig/patches/0010-llvm-Implement-bigint-to-LLVM-int-for-32-bit-compile.patch94
-rw-r--r--Ports/zig/patches/0011-Add-SerenityOS-target.patch215
-rw-r--r--Ports/zig/patches/0012-Implement-SerenityOS-support-in-std.patch616
-rw-r--r--Ports/zig/patches/0013-build-Adjust-build-process-for-SerenityOS.patch98
-rw-r--r--Ports/zig/patches/ReadMe.md109
-rw-r--r--Ports/zig/scripts/constants.txt193
-rw-r--r--Ports/zig/scripts/generate-serenity-constants.zig50
18 files changed, 1532 insertions, 0 deletions
diff --git a/Ports/zig/.gitignore b/Ports/zig/.gitignore
new file mode 100644
index 0000000000..dbf8b89d41
--- /dev/null
+++ b/Ports/zig/.gitignore
@@ -0,0 +1 @@
+!scripts/*
diff --git a/Ports/zig/package.sh b/Ports/zig/package.sh
new file mode 100755
index 0000000000..9a62cea8c6
--- /dev/null
+++ b/Ports/zig/package.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env -S bash ../.port_include.sh
+
+port='zig'
+version='0.11.0-dev.670+f7fea080b'
+files='https://github.com/ziglang/zig-bootstrap/archive/b9a466fd23d7777e1b3b87d49074ce66370fb7b3.tar.gz zig-bootstrap-b9a466f.tar.gz 84cf91d727c53ef49220ea6b2864dae3bd48e5e5a73be95bf3672c38a72b0946'
+auth_type='sha256'
+workdir='zig-bootstrap-b9a466fd23d7777e1b3b87d49074ce66370fb7b3'
+
+post_fetch() {
+ run mkdir -p out
+ run cp -r "${PORT_META_DIR}/scripts" out/
+}
+
+build() {
+ host_env
+ cd "${workdir}"
+ ./build "${SERENITY_ARCH}-serenity-none" "native"
+}
+
+install() {
+ zig_install_dir="${workdir}/out/zig-${SERENITY_ARCH}-serenity-none-native"
+
+ mkdir -p "${DESTDIR}/usr/local/bin/."
+ mkdir -p "${DESTDIR}/usr/local/lib/."
+ cp -rv "${zig_install_dir}/bin/"* "${DESTDIR}/usr/local/bin/"
+ cp -rv "${zig_install_dir}/lib/"* "${DESTDIR}/usr/local/lib/"
+}
diff --git a/Ports/zig/patches/0001-Add-support-for-building-LLVM-on-SerenityOS.patch b/Ports/zig/patches/0001-Add-support-for-building-LLVM-on-SerenityOS.patch
new file mode 120000
index 0000000000..b9d528427b
--- /dev/null
+++ b/Ports/zig/patches/0001-Add-support-for-building-LLVM-on-SerenityOS.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0001-Support-Add-support-for-building-LLVM-on-SerenityOS.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0002-Add-triple-for-SerenityOS.patch b/Ports/zig/patches/0002-Add-triple-for-SerenityOS.patch
new file mode 120000
index 0000000000..bf126fa344
--- /dev/null
+++ b/Ports/zig/patches/0002-Add-triple-for-SerenityOS.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0002-Triple-Add-triple-for-SerenityOS.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0003-Add-support-for-SerenityOS.patch b/Ports/zig/patches/0003-Add-support-for-SerenityOS.patch
new file mode 120000
index 0000000000..1514652360
--- /dev/null
+++ b/Ports/zig/patches/0003-Add-support-for-SerenityOS.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0003-Driver-Add-support-for-SerenityOS.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0004-Default-to-ftls-model-initial-exec-on-SerenityOS.patch b/Ports/zig/patches/0004-Default-to-ftls-model-initial-exec-on-SerenityOS.patch
new file mode 120000
index 0000000000..de36d10ec9
--- /dev/null
+++ b/Ports/zig/patches/0004-Default-to-ftls-model-initial-exec-on-SerenityOS.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0004-Driver-Default-to-ftls-model-initial-exec-on-Serenit.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0005-Add-support-for-SerenityOS.patch b/Ports/zig/patches/0005-Add-support-for-SerenityOS.patch
new file mode 100644
index 0000000000..9f0f52eb5c
--- /dev/null
+++ b/Ports/zig/patches/0005-Add-support-for-SerenityOS.patch
@@ -0,0 +1,121 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: sin-ack <sin-ack@protonmail.com>
+Date: Tue, 27 Sep 2022 00:08:46 +0000
+Subject: [PATCH] Add support for SerenityOS
+
+This commit teaches libc++ about what features are available in our
+LibC, namely:
+* We do not have locale support, so no-op shims should be used in place
+ of the C locale API.
+* The number of errno constants defined by us is given by the value of
+ the `ELAST` macro.
+* Multithreading is implemented though the pthread library.
+* Use libc++'s builtin character type table instead of the one provided
+ by LibC as there's a lot of extra porting work to convince the rest of
+ locale.cpp to use our character type table properly.
+
+This commit is an adaptation of the LLVM patch by Daniel Bertalan to fit
+the layout of the zig-bootstrap project.
+
+Co-Authored-By: Daniel Bertalan <dani@danielbertalan.dev>
+---
+ zig/lib/libcxx/include/__config | 5 ++--
+ zig/lib/libcxx/include/__locale | 2 ++
+ .../include/__support/serenity/xlocale.h | 24 +++++++++++++++++++
+ zig/lib/libcxx/include/locale | 2 +-
+ zig/lib/libcxx/src/include/config_elast.h | 2 ++
+ 5 files changed, 32 insertions(+), 3 deletions(-)
+ create mode 100644 zig/lib/libcxx/include/__support/serenity/xlocale.h
+
+diff --git a/zig/lib/libcxx/include/__config b/zig/lib/libcxx/include/__config
+index d9a47343dad1faf52826abbcd6da7578cec9932a..74a8970eddfaec23f421c3edbe974f77ad055e27 100644
+--- a/zig/lib/libcxx/include/__config
++++ b/zig/lib/libcxx/include/__config
+@@ -910,7 +910,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
+ defined(__sun__) || \
+ defined(__MVS__) || \
+ defined(_AIX) || \
+- defined(__EMSCRIPTEN__)
++ defined(__EMSCRIPTEN__) || \
++ defined(__serenity__)
+ // clang-format on
+ # define _LIBCPP_HAS_THREAD_API_PTHREAD
+ # elif defined(__Fuchsia__)
+@@ -988,7 +989,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
+ # endif
+
+ # if defined(__BIONIC__) || defined(__NuttX__) || defined(__Fuchsia__) || defined(__wasi__) || \
+- defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__)
++ defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__) || defined(__serenity__)
+ # define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
+ # endif
+
+diff --git a/zig/lib/libcxx/include/__locale b/zig/lib/libcxx/include/__locale
+index 40f9a3ff57c22635254be654227333b2a10eca6a..1c499c078b44a49abead17ce566801b4c34733f3 100644
+--- a/zig/lib/libcxx/include/__locale
++++ b/zig/lib/libcxx/include/__locale
+@@ -42,6 +42,8 @@
+ # include <__support/musl/xlocale.h>
+ #elif defined(_LIBCPP_HAS_MUSL_LIBC)
+ # include <__support/musl/xlocale.h>
++#elif defined(__serenity__)
++# include <__support/serenity/xlocale.h>
+ #endif
+
+ #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+diff --git a/zig/lib/libcxx/include/__support/serenity/xlocale.h b/zig/lib/libcxx/include/__support/serenity/xlocale.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..0f939d2f6989e2ad617145308d079776fe87b6ce
+--- /dev/null
++++ b/zig/lib/libcxx/include/__support/serenity/xlocale.h
+@@ -0,0 +1,24 @@
++//===----------------------------------------------------------------------===//
++//
++// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
++// See https://llvm.org/LICENSE.txt for license information.
++// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
++//
++//===----------------------------------------------------------------------===//
++
++#ifndef _LIBCPP_SUPPORT_SERENITY_XLOCALE_H
++#define _LIBCPP_SUPPORT_SERENITY_XLOCALE_H
++
++#if defined(__serenity__)
++
++#include <cstdlib>
++#include <clocale>
++#include <cwctype>
++#include <ctype.h>
++#include <__support/xlocale/__nop_locale_mgmt.h>
++#include <__support/xlocale/__posix_l_fallback.h>
++#include <__support/xlocale/__strtonum_fallback.h>
++
++#endif // __serenity__
++
++#endif
+diff --git a/zig/lib/libcxx/include/locale b/zig/lib/libcxx/include/locale
+index b01c66d0430f66ee74118e73296780bb864e920b..da29b7d00c709788facb049f417b6d5ccb5b70e1 100644
+--- a/zig/lib/libcxx/include/locale
++++ b/zig/lib/libcxx/include/locale
+@@ -217,7 +217,7 @@ template <class charT> class messages_byname;
+
+ #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
+ // Most unix variants have catopen. These are the specific ones that don't.
+-# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__)
++# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) && !defined(__serenity__)
+ # define _LIBCPP_HAS_CATOPEN 1
+ # include <nl_types.h>
+ # endif
+diff --git a/zig/lib/libcxx/src/include/config_elast.h b/zig/lib/libcxx/src/include/config_elast.h
+index bef26ec5019eccab758733eb85a1f8a6fc404968..fbb2899b1939a2f9ce7a39337c99e48c7749f7f2 100644
+--- a/zig/lib/libcxx/src/include/config_elast.h
++++ b/zig/lib/libcxx/src/include/config_elast.h
+@@ -35,6 +35,8 @@
+ #define _LIBCPP_ELAST 4095
+ #elif defined(__APPLE__)
+ // No _LIBCPP_ELAST needed on Apple
++#elif defined(__serenity__)
++// No _LIBCPP_ELAST needed on SerenityOS
+ #elif defined(__sun__)
+ #define _LIBCPP_ELAST ESTALE
+ #elif defined(__MVS__)
diff --git a/Ports/zig/patches/0006-Allow-undefined-symbols-on-SerenityOS.patch b/Ports/zig/patches/0006-Allow-undefined-symbols-on-SerenityOS.patch
new file mode 120000
index 0000000000..910e63886f
--- /dev/null
+++ b/Ports/zig/patches/0006-Allow-undefined-symbols-on-SerenityOS.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0007-cmake-Allow-undefined-symbols-on-SerenityOS.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0007-Support-building-shared-libLLVM-and-libClang-for-Ser.patch b/Ports/zig/patches/0007-Support-building-shared-libLLVM-and-libClang-for-Ser.patch
new file mode 120000
index 0000000000..e23d2c8d68
--- /dev/null
+++ b/Ports/zig/patches/0007-Support-building-shared-libLLVM-and-libClang-for-Ser.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0008-cmake-Support-building-shared-libLLVM-and-libClang-f.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0008-Add-SerenityOS-to-config.guess.patch b/Ports/zig/patches/0008-Add-SerenityOS-to-config.guess.patch
new file mode 120000
index 0000000000..8b07a3602f
--- /dev/null
+++ b/Ports/zig/patches/0008-Add-SerenityOS-to-config.guess.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0010-Add-SerenityOS-to-config.guess.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0009-Prevent-the-use-of-POSIX-shm-on-SerenityOS.patch b/Ports/zig/patches/0009-Prevent-the-use-of-POSIX-shm-on-SerenityOS.patch
new file mode 120000
index 0000000000..7766daa29f
--- /dev/null
+++ b/Ports/zig/patches/0009-Prevent-the-use-of-POSIX-shm-on-SerenityOS.patch
@@ -0,0 +1 @@
+../../../Toolchain/Patches/llvm/0011-llvm-Prevent-the-use-of-POSIX-shm-on-SerenityOS.patch \ No newline at end of file
diff --git a/Ports/zig/patches/0010-llvm-Implement-bigint-to-LLVM-int-for-32-bit-compile.patch b/Ports/zig/patches/0010-llvm-Implement-bigint-to-LLVM-int-for-32-bit-compile.patch
new file mode 100644
index 0000000000..a173cda8ac
--- /dev/null
+++ b/Ports/zig/patches/0010-llvm-Implement-bigint-to-LLVM-int-for-32-bit-compile.patch
@@ -0,0 +1,94 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: sin-ack <sin-ack@users.noreply.github.com>
+Date: Sat, 1 Oct 2022 20:05:58 +0000
+Subject: [PATCH] llvm: Implement bigint-to-LLVM int for 32-bit compiler builds
+
+The conversion to DoubleLimb is necessary due to LLVM only accepting
+64-bit limbs for big integers. Since we need some space to store it, we
+also have to allocate. This is an unfortunate penalty that 32-bit
+compiler builds have to take.
+---
+ zig/lib/std/math/big/int.zig | 21 +++++++++++++++++++++
+ zig/src/codegen/llvm.zig | 28 ++++++++++++++++++++++++++--
+ 2 files changed, 47 insertions(+), 2 deletions(-)
+
+diff --git a/zig/lib/std/math/big/int.zig b/zig/lib/std/math/big/int.zig
+index 534e8a570d675aba91f8623a08859aa2d7d533fd..30db3f36df0311faef1eaba3d69a9785d9e50296 100644
+--- a/zig/lib/std/math/big/int.zig
++++ b/zig/lib/std/math/big/int.zig
+@@ -1899,6 +1899,27 @@ pub const Const = struct {
+ };
+ }
+
++ /// Convert each limb to a DoubleLimb and write it to `double_limbs`.
++ /// Return the slice of limbs that was used.
++ /// Asserts `double_limbs` is big enough to store the value.
++ pub fn toDoubleLimb(self: Const, double_limbs: []DoubleLimb) ![]DoubleLimb {
++ // TODO: Add tests (and check if this works on big-endian)!
++ assert(double_limbs.len >= (try std.math.divCeil(usize, self.limbs.len, 2)));
++
++ var i: usize = 0;
++ var double_limb_i: usize = 0;
++ while (i < self.limbs.len) : ({
++ i += 2;
++ double_limb_i += 1;
++ }) {
++ const most_significant: Limb = if (i + 1 == self.limbs.len) 0 else self.limbs[i + 1];
++ const least_significant = self.limbs[i];
++ double_limbs[double_limb_i] = @intCast(DoubleLimb, least_significant) | (@intCast(DoubleLimb, most_significant) << @bitSizeOf(Limb));
++ }
++
++ return double_limbs[0..double_limb_i];
++ }
++
+ pub fn dump(self: Const) void {
+ for (self.limbs[0..self.limbs.len]) |limb| {
+ std.debug.print("{x} ", .{limb});
+diff --git a/zig/src/codegen/llvm.zig b/zig/src/codegen/llvm.zig
+index 4115a4870ea3f8731b929afd65f5111bee1f2983..e3ae805402e063341519ebeb7ee62c8717e45697 100644
+--- a/zig/src/codegen/llvm.zig
++++ b/zig/src/codegen/llvm.zig
+@@ -3241,8 +3241,20 @@ pub const DeclGen = struct {
+ @intCast(c_uint, bigint.limbs.len),
+ bigint.limbs.ptr,
+ );
++ } else {
++ // Because LLVM only accepts 64-bit limbs for constIntOfArbitraryPrecision, we must convert to double-limb here (and allocate to do so).
++ // You (yes, you!) can fix this by making LLVM accept 32-bit limbs for creating an integer of arbitrary precision.
++ const double_limb_count = math.divCeil(usize, bigint.limbs.len, 2) catch return Error.CodegenFail;
++ var double_limb_space = try dg.gpa.alloc(math.big.DoubleLimb, double_limb_count);
++ defer dg.gpa.free(double_limb_space);
++
++ _ = bigint.toDoubleLimb(double_limb_space) catch return Error.CodegenFail;
++
++ break :v llvm_type.constIntOfArbitraryPrecision(
++ @intCast(c_uint, double_limb_count),
++ double_limb_space.ptr,
++ );
+ }
+- @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
+ };
+ if (!bigint.positive) {
+ return llvm.constNeg(unsigned_val);
+@@ -3269,8 +3281,20 @@ pub const DeclGen = struct {
+ @intCast(c_uint, bigint.limbs.len),
+ bigint.limbs.ptr,
+ );
++ } else {
++ // Because LLVM only accepts 64-bit limbs for constIntOfArbitraryPrecision, we must convert to double-limb here (and allocate to do so).
++ // You (yes, you!) can fix this by making LLVM accept 32-bit limbs for creating an integer of arbitrary precision.
++ const double_limb_count = math.divCeil(usize, bigint.limbs.len, 2) catch return Error.CodegenFail;
++ var double_limb_space = try dg.gpa.alloc(math.big.DoubleLimb, double_limb_count);
++ defer dg.gpa.free(double_limb_space);
++
++ _ = bigint.toDoubleLimb(double_limb_space) catch return Error.CodegenFail;
++
++ break :v llvm_type.constIntOfArbitraryPrecision(
++ @intCast(c_uint, double_limb_count),
++ double_limb_space.ptr,
++ );
+ }
+- @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
+ };
+ if (!bigint.positive) {
+ return llvm.constNeg(unsigned_val);
diff --git a/Ports/zig/patches/0011-Add-SerenityOS-target.patch b/Ports/zig/patches/0011-Add-SerenityOS-target.patch
new file mode 100644
index 0000000000..06a3f6ad99
--- /dev/null
+++ b/Ports/zig/patches/0011-Add-SerenityOS-target.patch
@@ -0,0 +1,215 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: sin-ack <sin-ack@users.noreply.github.com>
+Date: Sun, 11 Dec 2022 17:18:09 +0000
+Subject: [PATCH] Add SerenityOS target
+
+Named "serenity" within the code to match what LLVM says.
+---
+ zig/lib/std/target.zig | 6 ++++++
+ zig/lib/std/zig/CrossTarget.zig | 2 ++
+ zig/src/codegen/llvm.zig | 2 ++
+ zig/src/codegen/llvm/bindings.zig | 1 +
+ zig/src/libc_installation.zig | 6 +++++-
+ zig/src/link/Elf.zig | 9 +++++++++
+ zig/src/target.zig | 5 ++++-
+ zig/src/type.zig | 1 +
+ zig/src/zig_llvm.h | 3 ++-
+ 9 files changed, 32 insertions(+), 3 deletions(-)
+
+diff --git a/zig/lib/std/target.zig b/zig/lib/std/target.zig
+index 49a7bd1c7dd1334067ed3b867f5ada7b99538355..af7b14be8e01509280d59b0196ff3a3040a48bf6 100644
+--- a/zig/lib/std/target.zig
++++ b/zig/lib/std/target.zig
+@@ -60,6 +60,7 @@ pub const Target = struct {
+ glsl450,
+ vulkan,
+ plan9,
++ serenity,
+ other,
+
+ pub fn isDarwin(tag: Tag) bool {
+@@ -267,6 +268,7 @@ pub const Target = struct {
+ .glsl450, // TODO: GLSL versions
+ .vulkan,
+ .plan9,
++ .serenity,
+ .other,
+ => return .{ .none = {} },
+
+@@ -410,6 +412,7 @@ pub const Target = struct {
+ .openbsd,
+ .haiku,
+ .solaris,
++ .serenity,
+ => true,
+
+ .linux,
+@@ -563,6 +566,7 @@ pub const Target = struct {
+ .watchos,
+ .driverkit,
+ .shadermodel,
++ .serenity,
+ => return .none,
+ }
+ }
+@@ -1740,6 +1744,8 @@ pub const Target = struct {
+ // TODO revisit when multi-arch for Haiku is available
+ .haiku => return copy(&result, "/system/runtime_loader"),
+
++ .serenity => return copy(&result, "/usr/lib/Loader.so"),
++
+ // TODO go over each item in this list and either move it to the above list, or
+ // implement the standard dynamic linker path code for it.
+ .ananas,
+diff --git a/zig/lib/std/zig/CrossTarget.zig b/zig/lib/std/zig/CrossTarget.zig
+index aad0cb42f252d04b858133ba6ec598aa043f1c1c..a401ba49ee7afde0279c537a890cd33d3fe4815e 100644
+--- a/zig/lib/std/zig/CrossTarget.zig
++++ b/zig/lib/std/zig/CrossTarget.zig
+@@ -137,6 +137,7 @@ fn updateOsVersionRange(self: *CrossTarget, os: Target.Os) void {
+ .glsl450,
+ .vulkan,
+ .plan9,
++ .serenity,
+ .other,
+ => {
+ self.os_version_min = .{ .none = {} };
+@@ -693,6 +694,7 @@ fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const
+ .plan9,
+ .driverkit,
+ .shadermodel,
++ .serenity,
+ .other,
+ => return error.InvalidOperatingSystemVersion,
+
+diff --git a/zig/src/codegen/llvm.zig b/zig/src/codegen/llvm.zig
+index e3ae805402e063341519ebeb7ee62c8717e45697..ba4f2c0840f15b7776f4d8768d3a525551069484 100644
+--- a/zig/src/codegen/llvm.zig
++++ b/zig/src/codegen/llvm.zig
+@@ -143,6 +143,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
+ .watchos => "watchos",
+ .driverkit => "driverkit",
+ .shadermodel => "shadermodel",
++ .serenity => "serenity",
+ .opencl,
+ .glsl450,
+ .vulkan,
+@@ -246,6 +247,7 @@ pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType {
+ .emscripten => .Emscripten,
+ .driverkit => .DriverKit,
+ .shadermodel => .ShaderModel,
++ .serenity => .Serenity,
+ };
+ }
+
+diff --git a/zig/src/codegen/llvm/bindings.zig b/zig/src/codegen/llvm/bindings.zig
+index 90d0f51c7b36f7f3df19594933034f483a24c757..f11d1a6743493e18d5b4c2c6f19356d249f88cba 100644
+--- a/zig/src/codegen/llvm/bindings.zig
++++ b/zig/src/codegen/llvm/bindings.zig
+@@ -1287,6 +1287,7 @@ pub const OSType = enum(c_int) {
+ WASI,
+ Emscripten,
+ ShaderModel,
++ Serenity,
+ };
+
+ pub const ArchType = enum(c_int) {
+diff --git a/zig/src/libc_installation.zig b/zig/src/libc_installation.zig
+index 0a50f970123fbf2298cdf3666a1e7d6a59130e20..af50f4ebfaa783328513d9d9086cdfa9aee83b76 100644
+--- a/zig/src/libc_installation.zig
++++ b/zig/src/libc_installation.zig
+@@ -8,6 +8,7 @@ const build_options = @import("build_options");
+ const is_darwin = builtin.target.isDarwin();
+ const is_windows = builtin.target.os.tag == .windows;
+ const is_haiku = builtin.target.os.tag == .haiku;
++const is_serenity = builtin.target.os.tag == .serenity;
+
+ const log = std.log.scoped(.libc_installation);
+
+@@ -205,6 +206,9 @@ pub const LibCInstallation = struct {
+ try self.findNativeIncludeDirPosix(args);
+ try self.findNativeCrtBeginDirHaiku(args);
+ self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib");
++ } else if (is_serenity) {
++ try self.findNativeIncludeDirPosix(args);
++ self.crt_dir = try args.allocator.dupeZ(u8, "/usr/lib");
+ } else if (std.process.can_spawn) {
+ try self.findNativeIncludeDirPosix(args);
+ switch (builtin.target.os.tag) {
+@@ -308,7 +312,7 @@ pub const LibCInstallation = struct {
+ const include_dir_example_file = if (is_haiku) "posix/stdlib.h" else "stdlib.h";
+ const sys_include_dir_example_file = if (is_windows)
+ "sys\\types.h"
+- else if (is_haiku)
++ else if (is_haiku or is_serenity)
+ "errno.h"
+ else
+ "sys/errno.h";
+diff --git a/zig/src/link/Elf.zig b/zig/src/link/Elf.zig
+index ebb1cbdfb8efc867d34e0315256e6efa4c90a035..46c61a10fefd8aa2efe43c023e261e97197dc4b3 100644
+--- a/zig/src/link/Elf.zig
++++ b/zig/src/link/Elf.zig
+@@ -3152,6 +3152,15 @@ const CsuObjects = struct {
+ .static_pie => result.set( "rcrt0.o", null, "crtbegin.o", "crtend.o", null ),
+ // zig fmt: on
+ },
++ .serenity => switch (mode) {
++ // zig fmt: off
++ .dynamic_lib => result.set( "crt0_shared.o", "crti.o", null, null, "crtn.o" ),
++ .dynamic_exe,
++ .dynamic_pie,
++ .static_exe,
++ .static_pie => result.set( "crt0.o", "crti.o", null, null, "crtn.o" ),
++ // zig fmt: on
++ },
+ .haiku => switch (mode) {
+ // zig fmt: off
+ .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
+diff --git a/zig/src/target.zig b/zig/src/target.zig
+index 836791a1d1d7c69655d056b39ed58f2399ed12f4..02c9a23d9ac0dfa870defba94c8b302a5dab7927 100644
+--- a/zig/src/target.zig
++++ b/zig/src/target.zig
+@@ -187,7 +187,7 @@ pub fn libcNeedsLibUnwind(target: std.Target) bool {
+ }
+
+ pub fn requiresPIE(target: std.Target) bool {
+- return target.isAndroid() or target.isDarwin() or target.os.tag == .openbsd;
++ return target.isAndroid() or target.isDarwin() or target.os.tag == .openbsd or target.os.tag == .serenity;
+ }
+
+ /// This function returns whether non-pic code is completely invalid on the given target.
+@@ -472,6 +472,9 @@ pub fn libcFullLinkFlags(target: std.Target) []const []const u8 {
+ "-lpthread",
+ "-lc",
+ },
++ .serenity => &[_][]const u8{
++ "-lc",
++ },
+ else => switch (target.abi) {
+ .android => &[_][]const u8{
+ "-lm",
+diff --git a/zig/src/type.zig b/zig/src/type.zig
+index 1aefa8f7a1c77ddf58b1cb7271b57db6618704fb..13f8dc1879ed37e0452c78c698b72fcb3b955ec2 100644
+--- a/zig/src/type.zig
++++ b/zig/src/type.zig
+@@ -6772,6 +6772,7 @@ pub const CType = enum {
+ .ananas,
+ .fuchsia,
+ .minix,
++ .serenity,
+ => switch (target.cpu.arch) {
+ .msp430 => switch (self) {
+ .short, .ushort, .int, .uint => return 16,
+diff --git a/zig/src/zig_llvm.h b/zig/src/zig_llvm.h
+index 7f9bd0a1619d30239a1ab92c3b9675d8c1bdb987..dc1561421fa0afedf892ddbdf698b57aeb83af72 100644
+--- a/zig/src/zig_llvm.h
++++ b/zig/src/zig_llvm.h
+@@ -468,7 +468,8 @@ enum ZigLLVM_OSType {
+ ZigLLVM_WASI, // Experimental WebAssembly OS
+ ZigLLVM_Emscripten,
+ ZigLLVM_ShaderModel, // DirectX ShaderModel
+- ZigLLVM_LastOSType = ZigLLVM_ShaderModel
++ ZigLLVM_Serenity, // Well hello friends! :^)
++ ZigLLVM_LastOSType = ZigLLVM_Serenity
+ };
+
+ // Synchronize with target.cpp::abi_list
diff --git a/Ports/zig/patches/0012-Implement-SerenityOS-support-in-std.patch b/Ports/zig/patches/0012-Implement-SerenityOS-support-in-std.patch
new file mode 100644
index 0000000000..dad707d1b6
--- /dev/null
+++ b/Ports/zig/patches/0012-Implement-SerenityOS-support-in-std.patch
@@ -0,0 +1,616 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: sin-ack <sin-ack@users.noreply.github.com>
+Date: Sun, 30 Oct 2022 19:30:50 +0000
+Subject: [PATCH] Implement SerenityOS support in std
+
+---
+ zig/lib/std/Thread.zig | 2 +-
+ zig/lib/std/c.zig | 1 +
+ zig/lib/std/c/serenity.zig | 396 +++++++++++++++++++++++++++
+ zig/lib/std/c/serenity/constants.zig | 6 +
+ zig/lib/std/debug.zig | 3 +-
+ zig/lib/std/fs.zig | 72 ++++-
+ zig/lib/std/fs/get_app_data_dir.zig | 2 +-
+ zig/lib/std/os.zig | 3 +-
+ 8 files changed, 479 insertions(+), 6 deletions(-)
+ create mode 100644 zig/lib/std/c/serenity.zig
+ create mode 100644 zig/lib/std/c/serenity/constants.zig
+
+diff --git a/zig/lib/std/Thread.zig b/zig/lib/std/Thread.zig
+index e2e17a29259e1e2cf323ad90451f6fe7906e12a9..125e63bfd138a5a08653f4c815846c42e8eca3c5 100644
+--- a/zig/lib/std/Thread.zig
++++ b/zig/lib/std/Thread.zig
+@@ -617,7 +617,7 @@ const PosixThreadImpl = struct {
+ };
+ return @intCast(usize, count);
+ },
+- .solaris => {
++ .solaris, .serenity => {
+ // The "proper" way to get the cpu count would be to query
+ // /dev/kstat via ioctls, and traverse a linked list for each
+ // cpu.
+diff --git a/zig/lib/std/c.zig b/zig/lib/std/c.zig
+index 5f03f1c61902a191de87b49f0dcbdfec4a872d34..92c4bfcccb6bf45fcd8df748d346c8ec0dc84208 100644
+--- a/zig/lib/std/c.zig
++++ b/zig/lib/std/c.zig
+@@ -54,6 +54,7 @@ pub usingnamespace switch (builtin.os.tag) {
+ .minix => @import("c/minix.zig"),
+ .emscripten => @import("c/emscripten.zig"),
+ .wasi => @import("c/wasi.zig"),
++ .serenity => @import("c/serenity.zig"),
+ else => struct {},
+ };
+
+diff --git a/zig/lib/std/c/serenity.zig b/zig/lib/std/c/serenity.zig
+new file mode 100644
+index 0000000000000000000000000000000000000000..057813c1b13fcedc87271003220c42da7ef36e0e
+--- /dev/null
++++ b/zig/lib/std/c/serenity.zig
+@@ -0,0 +1,396 @@
++pub const std = @import("std");
++pub const SerenityConstants = @import("serenity/constants.zig");
++
++pub const fd_t = c_int;
++pub const dev_t = u32;
++pub const ino_t = u64;
++pub const off_t = i64;
++pub const nlink_t = u32;
++
++pub const E = enum(i32) {
++ SUCCESS = SerenityConstants.ESUCCESS,
++ PERM = SerenityConstants.EPERM,
++ NOENT = SerenityConstants.ENOENT,
++ SRCH = SerenityConstants.ESRCH,
++ INTR = SerenityConstants.EINTR,
++ IO = SerenityConstants.EIO,
++ NXIO = SerenityConstants.ENXIO,
++ @"2BIG" = SerenityConstants.E2BIG,
++ NOEXEC = SerenityConstants.ENOEXEC,
++ BADF = SerenityConstants.EBADF,
++ CHILD = SerenityConstants.ECHILD,
++ AGAIN = SerenityConstants.EAGAIN,
++ NOMEM = SerenityConstants.ENOMEM,
++ ACCES = SerenityConstants.EACCES,
++ FAULT = SerenityConstants.EFAULT,
++ NOTBLK = SerenityConstants.ENOTBLK,
++ BUSY = SerenityConstants.EBUSY,
++ EXIST = SerenityConstants.EEXIST,
++ XDEV = SerenityConstants.EXDEV,
++ NODEV = SerenityConstants.ENODEV,
++ NOTDIR = SerenityConstants.ENOTDIR,
++ ISDIR = SerenityConstants.EISDIR,
++ INVAL = SerenityConstants.EINVAL,
++ NFILE = SerenityConstants.ENFILE,
++ MFILE = SerenityConstants.EMFILE,
++ NOTTY = SerenityConstants.ENOTTY,
++ TXTBSY = SerenityConstants.ETXTBSY,
++ FBIG = SerenityConstants.EFBIG,
++ NOSPC = SerenityConstants.ENOSPC,
++ SPIPE = SerenityConstants.ESPIPE,
++ ROFS = SerenityConstants.EROFS,
++ MLINK = SerenityConstants.EMLINK,
++ PIPE = SerenityConstants.EPIPE,
++ RANGE = SerenityConstants.ERANGE,
++ NAMETOOLONG = SerenityConstants.ENAMETOOLONG,
++ LOOP = SerenityConstants.ELOOP,
++ OVERFLOW = SerenityConstants.EOVERFLOW,
++ OPNOTSUPP = SerenityConstants.EOPNOTSUPP,
++ NOSYS = SerenityConstants.ENOSYS,
++ NOTIMPL = SerenityConstants.ENOTIMPL,
++ AFNOSUPPORT = SerenityConstants.EAFNOSUPPORT,
++ NOTSOCK = SerenityConstants.ENOTSOCK,
++ ADDRINUSE = SerenityConstants.EADDRINUSE,
++ NOTEMPTY = SerenityConstants.ENOTEMPTY,
++ DOM = SerenityConstants.EDOM,
++ CONNREFUSED = SerenityConstants.ECONNREFUSED,
++ HOSTDOWN = SerenityConstants.EHOSTDOWN,
++ ADDRNOTAVAIL = SerenityConstants.EADDRNOTAVAIL,
++ ISCONN = SerenityConstants.EISCONN,
++ CONNABORTED = SerenityConstants.ECONNABORTED,
++ ALREADY = SerenityConstants.EALREADY,
++ CONNRESET = SerenityConstants.ECONNRESET,
++ DESTADDRREQ = SerenityConstants.EDESTADDRREQ,
++ HOSTUNREACH = SerenityConstants.EHOSTUNREACH,
++ ILSEQ = SerenityConstants.EILSEQ,
++ MSGSIZE = SerenityConstants.EMSGSIZE,
++ NETDOWN = SerenityConstants.ENETDOWN,
++ NETUNREACH = SerenityConstants.ENETUNREACH,
++ NETRESET = SerenityConstants.ENETRESET,
++ NOBUFS = SerenityConstants.ENOBUFS,
++ NOLCK = SerenityConstants.ENOLCK,
++ NOMSG = SerenityConstants.ENOMSG,
++ NOPROTOOPT = SerenityConstants.ENOPROTOOPT,
++ NOTCONN = SerenityConstants.ENOTCONN,
++ SHUTDOWN = SerenityConstants.ESHUTDOWN,
++ TOOMANYREFS = SerenityConstants.ETOOMANYREFS,
++ SOCKTNOSUPPORT = SerenityConstants.ESOCKTNOSUPPORT,
++ PROTONOSUPPORT = SerenityConstants.EPROTONOSUPPORT,
++ DEADLK = SerenityConstants.EDEADLK,
++ TIMEDOUT = SerenityConstants.ETIMEDOUT,
++ PROTOTYPE = SerenityConstants.EPROTOTYPE,
++ INPROGRESS = SerenityConstants.EINPROGRESS,
++ NOTHREAD = SerenityConstants.ENOTHREAD,
++ PROTO = SerenityConstants.EPROTO,
++ NOTSUP = SerenityConstants.ENOTSUP,
++ PFNOSUPPORT = SerenityConstants.EPFNOSUPPORT,
++ DIRINTOSELF = SerenityConstants.EDIRINTOSELF,
++ DQUOT = SerenityConstants.EDQUOT,
++ NOTRECOVERABLE = SerenityConstants.ENOTRECOVERABLE,
++ CANCELED = SerenityConstants.ECANCELED,
++ PROMISEVIOLATION = SerenityConstants.EPROMISEVIOLATION,
++ STALE = SerenityConstants.ESTALE,
++};
++
++pub const PATH_MAX = SerenityConstants.PATH_MAX;
++
++pub const time_t = i64;
++pub const timespec = struct {
++ tv_sec: time_t,
++ tv_nsec: c_long,
++};
++
++pub const mode_t = u16;
++
++pub const AT = struct {
++ pub const FDCWD = SerenityConstants.AT_FDCWD;
++ pub const SYMLINK_NOFOLLOW = SerenityConstants.AT_SYMLINK_NOFOLLOW;
++ pub const REMOVEDIR = SerenityConstants.AT_REMOVEDIR;
++};
++
++pub const _errno = struct {
++ extern "c" fn __errno_location() *c_int;
++}.__errno_location;
++
++pub const pthread_attr_t = *anyopaque;
++
++pub const LOCK = struct {
++ pub const SH = SerenityConstants.LOCK_SH;
++ pub const EX = SerenityConstants.LOCK_EX;
++ pub const UN = SerenityConstants.LOCK_UN;
++ pub const NB = SerenityConstants.LOCK_NB;
++};
++
++pub const STDIN_FILENO = SerenityConstants.STDIN_FILENO;
++pub const STDOUT_FILENO = SerenityConstants.STDOUT_FILENO;
++pub const STDERR_FILENO = SerenityConstants.STDERR_FILENO;
++
++pub const F = struct {
++ pub const DUPFD = SerenityConstants.F_DUPFD;
++ pub const GETFD = SerenityConstants.F_GETFD;
++ pub const SETFD = SerenityConstants.F_SETFD;
++ pub const GETFL = SerenityConstants.F_GETFL;
++ pub const SETFL = SerenityConstants.F_SETFL;
++ pub const ISTTY = SerenityConstants.F_ISTTY;
++ pub const GETLK = SerenityConstants.F_GETLK;
++ pub const SETLK = SerenityConstants.F_SETLK;
++ pub const SETLKW = SerenityConstants.F_SETLKW;
++};
++
++pub const FD_CLOEXEC = SerenityConstants.FD_CLOEXEC;
++
++pub const O = struct {
++ pub const RDONLY = SerenityConstants.O_RDONLY;
++ pub const WRONLY = SerenityConstants.O_WRONLY;
++ pub const RDWR = SerenityConstants.O_RDWR;
++ pub const ACCMODE = SerenityConstants.O_ACCMODE;
++ pub const EXEC = SerenityConstants.O_EXEC;
++ pub const CREAT = SerenityConstants.O_CREAT;
++ pub const EXCL = SerenityConstants.O_EXCL;
++ pub const NOCTTY = SerenityConstants.O_NOCTTY;
++ pub const TRUNC = SerenityConstants.O_TRUNC;
++ pub const APPEND = SerenityConstants.O_APPEND;
++ pub const NONBLOCK = SerenityConstants.O_NONBLOCK;
++ pub const DIRECTORY = SerenityConstants.O_DIRECTORY;
++ pub const NOFOLLOW = SerenityConstants.O_NOFOLLOW;
++ pub const CLOEXEC = SerenityConstants.O_CLOEXEC;
++ pub const DIRECT = SerenityConstants.O_DIRECT;
++ pub const SYNC = SerenityConstants.O_SYNC;
++};
++
++pub const R_OK = SerenityConstants.R_OK;
++pub const W_OK = SerenityConstants.W_OK;
++pub const X_OK = SerenityConstants.X_OK;
++pub const F_OK = SerenityConstants.F_OK;
++
++pub const CLOCK = struct {
++ pub const REALTIME = SerenityConstants.CLOCK_REALTIME;
++ pub const MONOTONIC = SerenityConstants.CLOCK_MONOTONIC;
++ pub const MONOTONIC_RAW = SerenityConstants.CLOCK_MONOTONIC_RAW;
++ pub const REALTIME_COARSE = SerenityConstants.CLOCK_REALTIME_COARSE;
++ pub const MONOTONIC_COARSE = SerenityConstants.CLOCK_MONOTONIC_COARSE;
++};
++
++pub const IOV_MAX = SerenityConstants.IOV_MAX;
++
++pub const pthread_mutex_t = struct {
++ lock: u32 = 0,
++ owner: ?std.c.pthread_t = null,
++ level: c_int = 0,
++ type: c_int = 0, // __PTHREAD_MUTEX_NORMAL
++};
++
++pub const pthread_cond_t = struct {
++ mutex: ?*pthread_mutex_t = null,
++ value: u32 = 0,
++ clockid: c_int = CLOCK.MONOTONIC_COARSE, // clockid_t
++};
++
++pub const uid_t = u32;
++pub const gid_t = u32;
++
++pub const blksize_t = u32;
++pub const blkcnt_t = u32;
++
++pub const Stat = struct {
++ dev: dev_t,
++ ino: ino_t,
++ mode: mode_t,
++ nlink: nlink_t,
++ uid: uid_t,
++ gid: gid_t,
++ rdev: dev_t,
++ size: off_t,
++ blksize: blksize_t,
++ blocks: blkcnt_t,
++ atim: timespec,
++ mtim: timespec,
++ ctim: timespec,
++
++ pub fn atime(self: @This()) timespec {
++ return self.atim;
++ }
++ pub fn mtime(self: @This()) timespec {
++ return self.mtim;
++ }
++ pub fn ctime(self: @This()) timespec {
++ return self.ctim;
++ }
++};
++
++pub const pid_t = c_int;
++
++pub const S = struct {
++ pub const IFMT = SerenityConstants.S_IFMT;
++ pub const IFDIR = SerenityConstants.S_IFDIR;
++ pub const IFCHR = SerenityConstants.S_IFCHR;
++ pub const IFBLK = SerenityConstants.S_IFBLK;
++ pub const IFREG = SerenityConstants.S_IFREG;
++ pub const IFIFO = SerenityConstants.S_IFIFO;
++ pub const IFLNK = SerenityConstants.S_IFLNK;
++ pub const IFSOCK = SerenityConstants.S_IFSOCK;
++
++ pub const ISUID = SerenityConstants.S_ISUID;
++ pub const ISGID = SerenityConstants.S_ISGID;
++ pub const ISVTX = SerenityConstants.S_ISVTX;
++ pub const IRUSR = SerenityConstants.S_IRUSR;
++ pub const IWUSR = SerenityConstants.S_IWUSR;
++ pub const IXUSR = SerenityConstants.S_IXUSR;
++ pub const IREAD = SerenityConstants.S_IREAD;
++ pub const IWRITE = SerenityConstants.S_IWRITE;
++ pub const IEXEC = SerenityConstants.S_IEXEC;
++ pub const IRGRP = SerenityConstants.S_IRGRP;
++ pub const IWGRP = SerenityConstants.S_IWGRP;
++ pub const IXGRP = SerenityConstants.S_IXGRP;
++ pub const IROTH = SerenityConstants.S_IROTH;
++ pub const IWOTH = SerenityConstants.S_IWOTH;
++ pub const IXOTH = SerenityConstants.S_IXOTH;
++
++ pub const IRWXU = SerenityConstants.S_IRWXU;
++
++ pub const IRWXG = SerenityConstants.S_IRWXG;
++ pub const IRWXO = SerenityConstants.S_IRWXO;
++
++ pub fn ISREG(m: u32) bool {
++ return m & IFMT == IFREG;
++ }
++
++ pub fn ISLNK(m: u32) bool {
++ return m & IFMT == IFLNK;
++ }
++
++ pub fn ISBLK(m: u32) bool {
++ return m & IFMT == IFBLK;
++ }
++
++ pub fn ISDIR(m: u32) bool {
++ return m & IFMT == IFDIR;
++ }
++
++ pub fn ISCHR(m: u32) bool {
++ return m & IFMT == IFCHR;
++ }
++
++ pub fn ISFIFO(m: u32) bool {
++ return m & IFMT == IFIFO;
++ }
++
++ pub fn ISSOCK(m: u32) bool {
++ return m & IFMT == IFSOCK;
++ }
++};
++
++pub const SEEK = struct {
++ pub const SET = SerenityConstants.SEEK_SET;
++ pub const CUR = SerenityConstants.SEEK_CUR;
++ pub const END = SerenityConstants.SEEK_END;
++};
++
++pub const POLL = struct {
++ pub const IN = SerenityConstants.POLLIN;
++ pub const RDNORM = SerenityConstants.POLLRDNORM;
++ pub const PRI = SerenityConstants.POLLPRI;
++ pub const OUT = SerenityConstants.POLLOUT;
++ pub const WRNORM = SerenityConstants.POLLWRNORM;
++ pub const ERR = SerenityConstants.POLLERR;
++ pub const HUP = SerenityConstants.POLLHUP;
++ pub const NVAL = SerenityConstants.POLLNVAL;
++ pub const WRBAND = SerenityConstants.POLLWRBAND;
++ pub const RDHUP = SerenityConstants.POLLRDHUP;
++};
++
++pub const pollfd = struct {
++ fd: c_int,
++ events: c_short,
++ revents: c_short,
++};
++
++pub const nfds_t = c_uint;
++
++pub const W = struct {
++ pub const NOHANG = SerenityConstants.WNOHANG;
++ pub const UNTRACED = SerenityConstants.WUNTRACED;
++ pub const STOPPED = SerenityConstants.WSTOPPED;
++ pub const EXITED = SerenityConstants.WEXITED;
++ pub const CONTINUED = SerenityConstants.WCONTINUED;
++ pub const NOWAIT = SerenityConstants.WNOWAIT;
++
++ pub fn EXITSTATUS(s: u32) u8 {
++ return @intCast(u8, (s & 0xff00) >> 8);
++ }
++
++ pub fn STOPSIG(s: u32) u32 {
++ return EXITSTATUS(s);
++ }
++
++ pub fn TERMSIG(s: u32) u32 {
++ return s & 0x7f;
++ }
++
++ pub fn IFEXITED(s: u32) bool {
++ return TERMSIG(s) == 0;
++ }
++
++ pub fn IFSTOPPED(s: u32) bool {
++ return (s & 0xff) == 0x7f;
++ }
++
++ pub fn IFSIGNALED(s: u32) bool {
++ return (@intCast(u8, (s & 0x7f) + 1) >> 1) > 0;
++ }
++
++ pub fn IFCONTINUED(s: u32) bool {
++ return s == 0xffff;
++ }
++};
++
++pub const dirent = extern struct {
++ d_ino: ino_t,
++ d_off: off_t,
++ d_reclen: c_ushort,
++ d_type: u8,
++ d_name: [256]u8,
++};
++pub extern "c" fn readdir_r(dir: *std.c.DIR, entry: *dirent, result: *?*dirent) i32;
++
++pub const PROT = struct {
++ pub const READ = SerenityConstants.PROT_READ;
++ pub const WRITE = SerenityConstants.PROT_WRITE;
++ pub const EXEC = SerenityConstants.PROT_EXEC;
++ pub const NONE = SerenityConstants.PROT_NONE;
++};
++
++pub const MAP = struct {
++ pub const FILE = SerenityConstants.MAP_FILE;
++ pub const SHARED = SerenityConstants.MAP_SHARED;
++ pub const PRIVATE = SerenityConstants.MAP_PRIVATE;
++ pub const FIXED = SerenityConstants.MAP_FIXED;
++ pub const ANONYMOUS = SerenityConstants.MAP_ANONYMOUS;
++ pub const ANON = SerenityConstants.MAP_ANON;
++ pub const STACK = SerenityConstants.MAP_STACK;
++ pub const NORESERVE = SerenityConstants.MAP_NORESERVE;
++ pub const RANDOMIZED = SerenityConstants.MAP_RANDOMIZED;
++ pub const PURGEABLE = SerenityConstants.MAP_PURGEABLE;
++ pub const FIXED_NOREPLACE = SerenityConstants.MAP_FIXED_NOREPLACE;
++ pub const FAILED = @intToPtr(*anyopaque, @bitCast(usize, @as(isize, -1)));
++};
++
++pub const MSF = struct {
++ pub const SYNC = SerenityConstants.MS_SYNC;
++ pub const ASYNC = SerenityConstants.MS_ASYNC;
++ pub const INVALIDATE = SerenityConstants.MS_INVALIDATE;
++};
++
++pub extern "c" fn sysconf(sc: c_int) c_long;
++pub const _SC = struct {
++ pub const NPROCESSORS_ONLN = SerenityConstants._SC_NPROCESSORS_ONLN;
++};
++
++pub const dl_phdr_info = extern struct {
++ dlpi_addr: std.elf.Addr,
++ dlpi_name: ?[*:0]const u8,
++ dlpi_phdr: [*]std.elf.Phdr,
++ dlpi_phnum: std.elf.Half,
++};
++pub const dl_iterate_phdr_callback = *const 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;
+diff --git a/zig/lib/std/c/serenity/constants.zig b/zig/lib/std/c/serenity/constants.zig
+new file mode 100644
+index 0000000000000000000000000000000000000000..94d7b1c091f7affb5c968738a8719cbbe526650b
+--- /dev/null
++++ b/zig/lib/std/c/serenity/constants.zig
+@@ -0,0 +1,6 @@
++comptime {
++ @compileError(
++ "A Zig compilation targeting SerenityOS can only be done by installing the SerenityOS Zig port. " ++
++ "This file is replaced by the actual POSIX constants during the port build process.",
++ );
++}
+diff --git a/zig/lib/std/debug.zig b/zig/lib/std/debug.zig
+index 90ceff3df157f3d94feddceae12de59fc2e3581d..5c25a8c9cebcb0cce01b229808ea67c57c968d5e 100644
+--- a/zig/lib/std/debug.zig
++++ b/zig/lib/std/debug.zig
+@@ -812,6 +812,7 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
+ .macos,
+ .windows,
+ .solaris,
++ .serenity,
+ => return DebugInfo.init(allocator),
+ else => return error.UnsupportedDebugInfo,
+ }
+@@ -1761,7 +1762,7 @@ pub const ModuleDebugInfo = switch (native_os) {
+ };
+ }
+ },
+- .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct {
++ .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris, .serenity => struct {
+ base_address: usize,
+ dwarf: DW.DwarfInfo,
+ mapped_memory: []align(mem.page_size) const u8,
+diff --git a/zig/lib/std/fs.zig b/zig/lib/std/fs.zig
+index e253aaff9e9505182db90c8fa08aa931dca8a0ba..cebf86fc05164ff311731deb4c75730d4dc84d27 100644
+--- a/zig/lib/std/fs.zig
++++ b/zig/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, .netbsd, .dragonfly, .openbsd, .haiku, .solaris, .serenity => 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.
+@@ -521,6 +521,69 @@ pub const IterableDir = struct {
+ self.first_iter = true;
+ }
+ },
++ .serenity => struct {
++ dir: Dir,
++ dir_ptr: *os.system.DIR,
++
++ const Self = @This();
++
++ pub const Error = IteratorError;
++
++ pub fn next(self: *Self) Error!?Entry {
++ const errno_location = os.system._errno();
++ start_over: while (true) {
++ // HACK: readdir_r currently doesn't work properly on
++ // SerenityOS. Until it does, we need to rely on
++ // readdir which has legacy errno behavior.
++ const saved_errno = errno_location.*;
++ errno_location.* = 0;
++ const entry = os.system.readdir(self.dir_ptr);
++ if (entry == null) {
++ if (errno_location.* != 0) {
++ switch (os.errno(-1)) {
++ .OVERFLOW => unreachable,
++ .BADF => unreachable,
++ .NOENT => unreachable,
++ else => |err| return os.unexpectedErrno(err),
++ }
++ }
++
++ // No error, just end of directory.
++ errno_location.* = saved_errno;
++ return null;
++ }
++
++ const name = mem.sliceTo(@ptrCast([*:0]u8, &entry.?.d_name), 0);
++ if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
++ continue :start_over;
++
++ const stat_info = os.fstatat(
++ self.dir.fd,
++ name,
++ os.AT.SYMLINK_NOFOLLOW,
++ ) catch |err| switch (err) {
++ error.NameTooLong => unreachable,
++ error.SymLinkLoop => unreachable,
++ error.FileNotFound => unreachable, // lost the race
++ else => |e| return e,
++ };
++ const entry_kind = switch (stat_info.mode & os.S.IFMT) {
++ os.S.IFIFO => Entry.Kind.NamedPipe,
++ os.S.IFCHR => Entry.Kind.CharacterDevice,
++ os.S.IFDIR => Entry.Kind.Directory,
++ os.S.IFBLK => Entry.Kind.BlockDevice,
++ os.S.IFREG => Entry.Kind.File,
++ os.S.IFLNK => Entry.Kind.SymLink,
++ os.S.IFSOCK => Entry.Kind.UnixDomainSocket,
++ else => Entry.Kind.Unknown,
++ };
++ return Entry{
++ .name = name,
++ .kind = entry_kind,
++ };
++ }
++ }
++ },
+ .haiku => struct {
+ dir: Dir,
+ buf: [1024]u8, // TODO align(@alignOf(os.dirent64)),
+@@ -906,6 +969,11 @@ pub const IterableDir = struct {
+ .buf = undefined,
+ .first_iter = first_iter_start_value,
+ },
++ .serenity => return Iterator{
++ .dir = self.dir,
++ // FIXME: Very small chance this may fail.
++ .dir_ptr = os.system.fdopendir(self.dir.fd).?,
++ },
+ .windows => return Iterator{
+ .dir = self.dir,
+ .index = 0,
+@@ -2941,7 +3009,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
+ return out_buffer[0..real_path.len];
+ }
+ switch (builtin.os.tag) {
+- .linux => return os.readlinkZ("/proc/self/exe", out_buffer),
++ .linux, .serenity => return os.readlinkZ("/proc/self/exe", out_buffer),
+ .solaris => return os.readlinkZ("/proc/self/path/a.out", out_buffer),
+ .freebsd, .dragonfly => {
+ var mib = [4]c_int{ os.CTL.KERN, os.KERN.PROC, os.KERN.PROC_PATHNAME, -1 };
+diff --git a/zig/lib/std/fs/get_app_data_dir.zig b/zig/lib/std/fs/get_app_data_dir.zig
+index 4f7ba9af623841cc8be7b6c48d55037f689fec8d..5a5b4de8aefe6962979a9a65f937cc35c78d7631 100644
+--- a/zig/lib/std/fs/get_app_data_dir.zig
++++ b/zig/lib/std/fs/get_app_data_dir.zig
+@@ -44,7 +44,7 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
+ };
+ return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
+ },
+- .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => {
++ .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .serenity => {
+ if (os.getenv("XDG_DATA_HOME")) |xdg| {
+ return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
+ }
+diff --git a/zig/lib/std/os.zig b/zig/lib/std/os.zig
+index f13ee03a967df2899aed1b935dd12975f5d07332..b1c174b774b40553c455d768c11ec6c752796a06 100644
+--- a/zig/lib/std/os.zig
++++ b/zig/lib/std/os.zig
+@@ -36,6 +36,7 @@ pub const haiku = std.c;
+ pub const netbsd = std.c;
+ pub const openbsd = std.c;
+ pub const solaris = std.c;
++pub const serenity = std.c;
+ pub const linux = @import("os/linux.zig");
+ pub const plan9 = @import("os/plan9.zig");
+ pub const uefi = @import("os/uefi.zig");
+@@ -5112,7 +5113,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
+ const len = mem.indexOfScalar(u8, out_buffer[0..], @as(u8, 0)) orelse MAX_PATH_BYTES;
+ return out_buffer[0..len];
+ },
+- .linux => {
++ .linux, .serenity => {
+ var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined;
+ const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{d}\x00", .{fd}) catch unreachable;
+
diff --git a/Ports/zig/patches/0013-build-Adjust-build-process-for-SerenityOS.patch b/Ports/zig/patches/0013-build-Adjust-build-process-for-SerenityOS.patch
new file mode 100644
index 0000000000..b6e180268f
--- /dev/null
+++ b/Ports/zig/patches/0013-build-Adjust-build-process-for-SerenityOS.patch
@@ -0,0 +1,98 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: sin-ack <sin-ack@users.noreply.github.com>
+Date: Sun, 11 Dec 2022 17:22:27 +0000
+Subject: [PATCH] build: Adjust build process for SerenityOS
+
+---
+ build | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 52 insertions(+), 1 deletion(-)
+
+diff --git a/build b/build
+index 5db75471ba94da22550136754c5ae71a56b4527c..2e757e44e852e41bd998ff70c2a9992b69d2910f 100755
+--- a/build
++++ b/build
+@@ -17,6 +17,7 @@ case $TARGET_OS_CMAKE in
+ freebsd) TARGET_OS_CMAKE="FreeBSD";;
+ windows) TARGET_OS_CMAKE="Windows";;
+ linux) TARGET_OS_CMAKE="Linux";;
++ serenity) TARGET_OS_CMAKE="Serenity";;
+ native) TARGET_OS_CMAKE="";;
+ esac
+
+@@ -62,10 +63,58 @@ cmake "$ROOTDIR/zig" \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DZIG_VERSION="$ZIG_VERSION"
+ cmake --build . --target install
++
++# Create a libc installation file so Zig knows where to look for headers and
++# libraries while compiling for the Serenity target.
++cat <<EOF > "$ROOTDIR/out/libc_installation.txt"
++include_dir=$SERENITY_INSTALL_ROOT/usr/include
++sys_include_dir=$SERENITY_INSTALL_ROOT/usr/include
++crt_dir=$SERENITY_INSTALL_ROOT/usr/lib
++msvc_lib_dir=
++kernel32_lib_dir=
++gcc_dir=
++EOF
++
++export ZIG_LIBC="$ROOTDIR/out/libc_installation.txt"
++
++# Create a CMakeToolchain.txt file to tell CMake about the SerenityOS platform.
++# Adapted from Toolchain/CMake/GNUToolchain.txt.in, with the tool settings
++# removed as zig-bootstrap overrides them manually with the cmake command.
++cat <<EOF > "$ROOTDIR/out/CMakeToolchain.txt"
++if (\${CMAKE_VERSION} VERSION_LESS "3.25.0")
++ list(APPEND CMAKE_MODULE_PATH "$SERENITY_SOURCE_DIR/Toolchain/CMake")
++endif()
++
++set(CMAKE_SYSTEM_NAME SerenityOS)
++set(CMAKE_SYSTEM_PROCESSOR "$SERENITY_ARCH")
++
++set(CMAKE_C_COMPILER_WORKS TRUE)
++set(CMAKE_CXX_COMPILER_WORKS TRUE)
++
++set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
++set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
++set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
++set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
++EOF
++
+
+ # Now we have Zig as a cross compiler.
+ ZIG="$ROOTDIR/out/host/bin/zig"
+
++# Create a serenity/constants.zig file. This package will overwrite the
++# constants.zig file in the upstream Zig in order to provide values for POSIX
++# constants.
++$ZIG run "$ROOTDIR/out/scripts/generate-serenity-constants.zig" \
++ -D__serenity__ \
++ -I"$SERENITY_INSTALL_ROOT/usr/include" \
++ > "$ROOTDIR/zig/lib/std/c/serenity/constants.zig"
++# HACK: Also copy this file over to the host Zig compiler in the prefix. It has
++# to be done this way because we can't generate the constants until we
++# have a Zig compiler, and by the time the host Zig compiler is built
++# the standard library sources have been copied into the prefix already.
++cp "$ROOTDIR/zig/lib/std/c/serenity/constants.zig" \
++ "$ROOTDIR/out/host/lib/zig/std/c/serenity/constants.zig"
++
+ # First cross compile zlib for the target, as we need the LLVM linked into
+ # the final zig binary to have zlib support enabled.
+ mkdir -p "$ROOTDIR/out/build-zlib-$TARGET-$MCPU"
+@@ -81,7 +130,8 @@ cmake "$ROOTDIR/zlib" \
+ -DCMAKE_ASM_COMPILER="$ZIG;cc;-fno-sanitize=all;-s;-target;$TARGET;-mcpu=$MCPU" \
+ -DCMAKE_RC_COMPILER="$ROOTDIR/out/host/bin/llvm-rc" \
+ -DCMAKE_AR="$ROOTDIR/out/host/bin/llvm-ar" \
+- -DCMAKE_RANLIB="$ROOTDIR/out/host/bin/llvm-ranlib"
++ -DCMAKE_RANLIB="$ROOTDIR/out/host/bin/llvm-ranlib" \
++ -DCMAKE_TOOLCHAIN_FILE="$ROOTDIR/out/CMakeToolchain.txt"
+ cmake --build . --target install
+
+ # Same deal for zstd.
+@@ -144,6 +194,7 @@ cmake "$ROOTDIR/llvm" \
+ -DCMAKE_RC_COMPILER="$ROOTDIR/out/host/bin/llvm-rc" \
+ -DCMAKE_AR="$ROOTDIR/out/host/bin/llvm-ar" \
+ -DCMAKE_RANLIB="$ROOTDIR/out/host/bin/llvm-ranlib" \
++ -DCMAKE_TOOLCHAIN_FILE="$ROOTDIR/out/CMakeToolchain.txt" \
+ -DLLVM_ENABLE_BACKTRACES=OFF \
+ -DLLVM_ENABLE_BINDINGS=OFF \
+ -DLLVM_ENABLE_CRASH_OVERRIDES=OFF \
diff --git a/Ports/zig/patches/ReadMe.md b/Ports/zig/patches/ReadMe.md
new file mode 100644
index 0000000000..bc394c16b9
--- /dev/null
+++ b/Ports/zig/patches/ReadMe.md
@@ -0,0 +1,109 @@
+# Patches for zig on SerenityOS
+
+## `0001-Add-support-for-building-LLVM-on-SerenityOS.patch`
+
+Add support for building LLVM on SerenityOS
+
+Adds SerenityOS `#ifdef`s for platform-specific code.
+
+We stub out wait4, as SerenityOS doesn't support querying a child
+process's resource usage information.
+
+## `0002-Add-triple-for-SerenityOS.patch`
+
+Add triple for SerenityOS
+
+
+## `0003-Add-support-for-SerenityOS.patch`
+
+Add support for SerenityOS
+
+Adds support for the `$arch-pc-serenity` target to the Clang front end.
+This makes the compiler look for libraries and headers in the right
+places, and enables some security mitigations like stack-smashing
+protection and position-independent code by default.
+
+## `0004-Default-to-ftls-model-initial-exec-on-SerenityOS.patch`
+
+Default to -ftls-model=initial-exec on SerenityOS
+
+This is a hack to make Clang use the initial-exec TLS model instead of
+the default local-exec when building code for Serenity.
+
+This patch should be removed when we implement proper TLS support.
+
+## `0005-Add-support-for-SerenityOS.patch`
+
+Add support for SerenityOS
+
+This commit teaches libc++ about what features are available in our
+LibC, namely:
+* We do not have locale support, so no-op shims should be used in place
+ of the C locale API.
+* The number of errno constants defined by us is given by the value of
+ the `ELAST` macro.
+* Multithreading is implemented though the pthread library.
+* Use libc++'s builtin character type table instead of the one provided
+ by LibC as there's a lot of extra porting work to convince the rest of
+ locale.cpp to use our character type table properly.
+
+This commit is an adaptation of the LLVM patch by Daniel Bertalan to fit
+the layout of the zig-bootstrap project.
+
+
+## `0006-Allow-undefined-symbols-on-SerenityOS.patch`
+
+Allow undefined symbols on SerenityOS
+
+Allow undefined symbols in LLVM libraries, which is needed because only
+stubs are available for SerenityOS libraries when libc++ and libunwind
+are built.
+
+## `0007-Support-building-shared-libLLVM-and-libClang-for-Ser.patch`
+
+Support building shared libLLVM and libClang for SerenityOS
+
+This patch tells CMake that the --whole-archive linker option should be
+used for specifying the archives whose members will constitute these
+shared libraries.
+
+Symbol versioning is disabled, as the SerenityOS loader doesn't support
+it, and the ELF sections that store version data would just waste space.
+
+## `0008-Add-SerenityOS-to-config.guess.patch`
+
+Add SerenityOS to config.guess
+
+
+## `0009-Prevent-the-use-of-POSIX-shm-on-SerenityOS.patch`
+
+Prevent the use of POSIX shm on SerenityOS
+
+POSIX shm is not supported by SerenityOS yet, so this causes a
+compilation error.
+
+## `0010-llvm-Implement-bigint-to-LLVM-int-for-32-bit-compile.patch`
+
+llvm: Implement bigint-to-LLVM int for 32-bit compiler builds
+
+The conversion to DoubleLimb is necessary due to LLVM only accepting
+64-bit limbs for big integers. Since we need some space to store it, we
+also have to allocate. This is an unfortunate penalty that 32-bit
+compiler builds have to take.
+
+## `0011-Add-SerenityOS-target.patch`
+
+Add SerenityOS target
+
+Named "serenity" within the code to match what LLVM says.
+
+## `0012-Implement-SerenityOS-support-in-std.patch`
+
+Implement SerenityOS support in std
+
+
+## `0013-build-Adjust-build-process-for-SerenityOS.patch`
+
+build: Adjust build process for SerenityOS
+
+
diff --git a/Ports/zig/scripts/constants.txt b/Ports/zig/scripts/constants.txt
new file mode 100644
index 0000000000..220a4436ab
--- /dev/null
+++ b/Ports/zig/scripts/constants.txt
@@ -0,0 +1,193 @@
+AT_FDCWD
+AT_REMOVEDIR
+AT_SYMLINK_NOFOLLOW
+CLOCK_MONOTONIC
+CLOCK_MONOTONIC_COARSE
+CLOCK_MONOTONIC_RAW
+CLOCK_REALTIME
+CLOCK_REALTIME_COARSE
+E2BIG
+EACCES
+EADDRINUSE
+EADDRNOTAVAIL
+EAFNOSUPPORT
+EAGAIN
+EALREADY
+EBADF
+EBUSY
+ECANCELED
+ECHILD
+ECONNABORTED
+ECONNREFUSED
+ECONNRESET
+EDEADLK
+EDESTADDRREQ
+EDIRINTOSELF
+EDOM
+EDQUOT
+EEXIST
+EFAULT
+EFBIG
+EHOSTDOWN
+EHOSTUNREACH
+EILSEQ
+EINPROGRESS
+EINTR
+EINVAL
+EIO
+EISCONN
+EISDIR
+ELOOP
+EMFILE
+EMLINK
+EMSGSIZE
+ENAMETOOLONG
+ENETDOWN
+ENETRESET
+ENETUNREACH
+ENFILE
+ENOBUFS
+ENODEV
+ENOENT
+ENOEXEC
+ENOLCK
+ENOMEM
+ENOMSG
+ENOPROTOOPT
+ENOSPC
+ENOSYS
+ENOTBLK
+ENOTCONN
+ENOTDIR
+ENOTEMPTY
+ENOTHREAD
+ENOTIMPL
+ENOTRECOVERABLE
+ENOTSOCK
+ENOTSUP
+ENOTTY
+ENXIO
+EOPNOTSUPP
+EOVERFLOW
+EPERM
+EPFNOSUPPORT
+EPIPE
+EPROMISEVIOLATION
+EPROTO
+EPROTONOSUPPORT
+EPROTOTYPE
+ERANGE
+EROFS
+ESHUTDOWN
+ESOCKTNOSUPPORT
+ESPIPE
+ESRCH
+ESTALE
+ESUCCESS
+ETIMEDOUT
+ETOOMANYREFS
+ETXTBSY
+EXDEV
+FD_CLOEXEC
+F_DUPFD
+F_GETFD
+F_GETFL
+F_GETLK
+F_ISTTY
+F_OK
+F_SETFD
+F_SETFL
+F_SETLK
+F_SETLKW
+IOV_MAX
+LOCK_EX
+LOCK_NB
+LOCK_SH
+LOCK_UN
+MAP_ANON
+MAP_ANONYMOUS
+MAP_FILE
+MAP_FIXED
+MAP_FIXED_NOREPLACE
+MAP_NORESERVE
+MAP_PRIVATE
+MAP_PURGEABLE
+MAP_RANDOMIZED
+MAP_SHARED
+MAP_STACK
+MS_ASYNC
+MS_INVALIDATE
+MS_SYNC
+O_ACCMODE
+O_APPEND
+O_CLOEXEC
+O_CREAT
+O_DIRECT
+O_DIRECTORY
+O_EXCL
+O_EXEC
+O_NOCTTY
+O_NOFOLLOW
+O_NONBLOCK
+O_RDONLY
+O_RDWR
+O_SYNC
+O_TRUNC
+O_WRONLY
+PATH_MAX
+POLLERR
+POLLHUP
+POLLIN
+POLLNVAL
+POLLOUT
+POLLPRI
+POLLRDHUP
+POLLRDNORM
+POLLWRBAND
+POLLWRNORM
+PROT_EXEC
+PROT_NONE
+PROT_READ
+PROT_WRITE
+R_OK
+SEEK_CUR
+SEEK_END
+SEEK_SET
+STDERR_FILENO
+STDIN_FILENO
+STDOUT_FILENO
+S_IEXEC
+S_IFBLK
+S_IFCHR
+S_IFDIR
+S_IFIFO
+S_IFLNK
+S_IFMT
+S_IFREG
+S_IFSOCK
+S_IREAD
+S_IRGRP
+S_IROTH
+S_IRUSR
+S_IRWXG
+S_IRWXO
+S_IRWXU
+S_ISGID
+S_ISUID
+S_ISVTX
+S_IWGRP
+S_IWOTH
+S_IWRITE
+S_IWUSR
+S_IXGRP
+S_IXOTH
+S_IXUSR
+WCONTINUED
+WEXITED
+WNOHANG
+WNOWAIT
+WSTOPPED
+WUNTRACED
+W_OK
+X_OK
+_SC_NPROCESSORS_ONLN
diff --git a/Ports/zig/scripts/generate-serenity-constants.zig b/Ports/zig/scripts/generate-serenity-constants.zig
new file mode 100644
index 0000000000..d87b6093ad
--- /dev/null
+++ b/Ports/zig/scripts/generate-serenity-constants.zig
@@ -0,0 +1,50 @@
+const std = @import("std");
+
+const SerenityIncludes = @cImport({
+ @cInclude("bits/pthread_integration.h");
+ @cInclude("dirent.h");
+ @cInclude("errno_codes.h");
+ @cInclude("fcntl.h");
+ @cInclude("limits.h");
+ @cInclude("link.h");
+ @cInclude("poll.h");
+ @cInclude("semaphore.h");
+ @cInclude("stdio.h");
+ @cInclude("sys/file.h");
+ @cInclude("sys/mman.h");
+ @cInclude("sys/stat.h");
+ @cInclude("sys/types.h");
+ @cInclude("sys/uio.h");
+ @cInclude("sys/wait.h");
+ @cInclude("time.h");
+ @cInclude("unistd.h");
+});
+
+const constant_file = @embedFile("./constants.txt");
+const constants = blk: {
+ @setEvalBranchQuota(10000);
+
+ var constant_list: []const []const u8 = &.{};
+ var constant_iterator = std.mem.tokenize(u8, constant_file, "\n");
+ while (constant_iterator.next()) |constant| {
+ constant_list = constant_list ++ &[_][]const u8{constant};
+ }
+
+ break :blk constant_list;
+};
+
+pub fn main() !void {
+ const writer = std.io.getStdOut().writer();
+
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer arena.deinit();
+ const allocator = arena.allocator();
+
+ inline for (constants) |constant| {
+ const value = @field(SerenityIncludes, constant);
+ const decl = try std.fmt.allocPrint(allocator, "pub const " ++ constant ++ " = {d};\n", .{value});
+ defer allocator.free(decl);
+
+ try writer.writeAll(decl);
+ }
+}