From db65dfd0d90facf7bd33c05f6a39c78305141ee1 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 24 Apr 2026 10:05:19 -0700 Subject: [PATCH] pkg/simdutf: better comments --- pkg/simdutf/build.zig | 35 +++++++++++++++++++---------------- pkg/simdutf/no_libc.zig | 9 +++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/pkg/simdutf/build.zig b/pkg/simdutf/build.zig index 72387a06f..073f4012a 100644 --- a/pkg/simdutf/build.zig +++ b/pkg/simdutf/build.zig @@ -1,19 +1,5 @@ const std = @import("std"); -const no_libc_flags = [_][]const u8{ - "-DSIMDUTF_NO_LIBC=1", - "-DSIMDUTF_LIBC_MEMCPY=simdutf_memcpy", - "-DSIMDUTF_LIBC_MEMMOVE=simdutf_memmove", - "-DSIMDUTF_LIBC_MEMSET=simdutf_memset", - "-DSIMDUTF_LIBC_MEMCMP=simdutf_memcmp", - "-DSIMDUTF_LIBC_STRLEN=simdutf_strlen", - "-DSIMDUTF_LIBC_GETENV=simdutf_getenv", -}; - -pub fn noLibcFlags() []const []const u8 { - return &no_libc_flags; -} - pub fn build(b: *std.Build) !void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); @@ -83,10 +69,10 @@ pub fn build(b: *std.Build) !void { } if (no_libc) { + lib.root_module.addCMacro("SIMDUTF_NO_LIBC", "1"); try flags.appendSlice(b.allocator, noLibcFlags()); - lib.root_module.addCMacro("SIMDUTF_NO_LIBC", "1"); - + // Build our object that has the libc replacement functions. const no_libc_obj = b.addObject(.{ .name = "simdutf_no_libc", .root_module = b.createModule(.{ @@ -140,3 +126,20 @@ pub fn build(b: *std.Build) !void { // test_step.dependOn(&tests_run.step); // } } + +/// These flags must be passed to any builds including simdutf headers +/// when no_libc is set, to provide the necessary macros to avoid libc +/// usage and to redirect libc calls to our Zig stdlib replacements. +pub fn noLibcFlags() []const []const u8 { + return &no_libc_flags; +} + +const no_libc_flags = [_][]const u8{ + "-DSIMDUTF_NO_LIBC=1", + "-DSIMDUTF_LIBC_MEMCPY=simdutf_memcpy", + "-DSIMDUTF_LIBC_MEMMOVE=simdutf_memmove", + "-DSIMDUTF_LIBC_MEMSET=simdutf_memset", + "-DSIMDUTF_LIBC_MEMCMP=simdutf_memcmp", + "-DSIMDUTF_LIBC_STRLEN=simdutf_strlen", + "-DSIMDUTF_LIBC_GETENV=simdutf_getenv", +}; diff --git a/pkg/simdutf/no_libc.zig b/pkg/simdutf/no_libc.zig index 4194712bd..0ac59714b 100644 --- a/pkg/simdutf/no_libc.zig +++ b/pkg/simdutf/no_libc.zig @@ -1,5 +1,6 @@ const std = @import("std"); +/// Copies `n` bytes from `src` to `dest`. The memory areas must not overlap. export fn simdutf_memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8 { const d = dest orelse return dest; const s = src orelse return dest; @@ -7,6 +8,8 @@ export fn simdutf_memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usi return dest; } +/// Copies `n` bytes from `src` to `dest`, correctly handling overlapping +/// memory regions. export fn simdutf_memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { const d = dest orelse return dest; const s = src orelse return dest; @@ -20,12 +23,14 @@ export fn simdutf_memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { return dest; } +/// Fills the first `n` bytes of `dest` with the byte value `c`. export fn simdutf_memset(dest: ?[*]u8, c: c_int, n: usize) ?[*]u8 { const d = dest orelse return dest; @memset(d[0..n], @as(u8, @intCast(c & 0xff))); return dest; } +/// Compares the first `n` bytes of `lhs` and `rhs`, returning -1, 0, or 1. export fn simdutf_memcmp(lhs: ?[*]const u8, rhs: ?[*]const u8, n: usize) c_int { const l = lhs orelse return 0; const r = rhs orelse return 0; @@ -37,11 +42,15 @@ export fn simdutf_memcmp(lhs: ?[*]const u8, rhs: ?[*]const u8, n: usize) c_int { }; } +/// Returns the length of the null-terminated string `s`, not including the +/// null byte. export fn simdutf_strlen(s: ?[*:0]const u8) usize { const str = s orelse return 0; return std.mem.len(str); } +/// Stub for `getenv` that always returns null, since there is no environment +/// in freestanding builds. export fn simdutf_getenv(_: ?[*:0]const u8) ?[*:0]const u8 { return null; }