diff --git a/Ports/AvailablePorts.md b/Ports/AvailablePorts.md index c104f37202..b8a827e7a6 100644 --- a/Ports/AvailablePorts.md +++ b/Ports/AvailablePorts.md @@ -273,6 +273,7 @@ This list is also available at [ports.serenityos.net](https://ports.serenityos.n | [`xash3d-fwgs`](xash3d-fwgs/) | Xash3D FWGS game engine | 2022.07.14 | https://github.com/FWGS/xash3d-fwgs | | [`xz`](xz/) | xz | 5.2.5 | https://tukaani.org/xz/ | | [`yasm`](yasm/) | Yasm Modular Assembler | 1.3.0 | https://yasm.tortall.net/ | +| [`zig`](zig/) | Zig programming language | 0.11.0-dev.670+f7fea080b | https://ziglang.org/ | | [`zlib`](zlib/) | zlib | 1.2.13 | https://www.zlib.net/ | | [`zsh`](zsh/) | Z Shell (Zsh) | 5.8.1 | https://www.zsh.org | | [`zstd`](zstd/) | Zstandard | 1.5.2 | https://facebook.github.io/zstd/ | 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 +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 +--- + 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 ++#include ++#include ++#include ++#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 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 + # 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 +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 +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 +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 +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 < "$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 < "$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); + } +}