From 7b5e18e23d4e6433b9f97244ab6c2bf059440485 Mon Sep 17 00:00:00 2001 From: Navid EMAD Date: Sat, 2 May 2026 10:00:42 +0200 Subject: [PATCH] build: relocate libidn2 strchrnul prototype into config.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the macOS strchrnul declaration from a side-channel header injected via -include into vendor/libidn2/config.h itself, gated on __APPLE__. config.h is the canonical place where libidn2 documents its HAVE_STRCHRNUL detection — co-locating the platform fallback prototype there mirrors gnulib's own approach (which declares missing symbols in its substituted ) and removes the per-platform build-flag asymmetry plus the dedicated include path. The Darwin-only strchrnul.c implementation is unchanged; build.zig now just adds it on Darwin without touching the lib/ flags array. Verified that on both `-target x86_64-macos.14.0` (no libc strchrnul) and `-target x86_64-macos.15.4` (libc has it) a TU mimicking lookup.c (`#include "config.h"` then call strchrnul) compiles cleanly with no implicit-declaration error and no redeclaration warning. --- build.zig | 21 +++++++++------------ vendor/libidn2/config.h | 11 +++++++++++ vendor/libidn2/darwin/strchrnul.c | 19 +++++++++---------- vendor/libidn2/darwin/strchrnul.h | 8 -------- 4 files changed, 29 insertions(+), 30 deletions(-) delete mode 100644 vendor/libidn2/darwin/strchrnul.h diff --git a/build.zig b/build.zig index efe8be81..d9f9dc89 100644 --- a/build.zig +++ b/build.zig @@ -551,26 +551,23 @@ fn buildLibidn2( // libc itself; on musl it would also need a separate -liconv. mod.linkSystemLibrary("iconv", .{}); - // libidn2's lib/lookup.c calls strchrnul() unconditionally — a glibc - // extension absent from macOS libc and not declared by . - // Upstream relies on gnulib substituting + linking - // gl/strchrnul.c; we don't wire up that overlay, so ship a small - // Darwin-only shim and inject its prototype via -include. - mod.addIncludePath(b.path("vendor/libidn2/darwin")); + // libidn2's lib/lookup.c calls strchrnul(), a glibc extension that + // macOS libc lacked before 15.4 and that lookup.c never gets a + // declaration for (it doesn't include ). Upstream solves + // this through gnulib's substituted + gl/strchrnul.c; + // we don't wire up that overlay. Provide our own implementation — + // the matching prototype is declared in vendor/libidn2/config.h + // under #ifdef __APPLE__, so every libidn2 TU sees it via the + // existing #include . lib.addCSourceFile(.{ .file = b.path("vendor/libidn2/darwin/strchrnul.c"), .flags = &.{}, }); } - const lib_flags: []const []const u8 = if (is_darwin) - &.{ "-DHAVE_CONFIG_H", "-DIDN2_STATIC", "-include", "strchrnul.h" } - else - &.{ "-DHAVE_CONFIG_H", "-DIDN2_STATIC" }; - lib.addCSourceFiles(.{ .root = dep.path("lib"), - .flags = lib_flags, + .flags = &.{ "-DHAVE_CONFIG_H", "-DIDN2_STATIC" }, .files = &.{ "bidi.c", "context.c", "data.c", "decode.c", "error.c", "free.c", "idna.c", "lookup.c", diff --git a/vendor/libidn2/config.h b/vendor/libidn2/config.h index 5ff0d577..f024f792 100644 --- a/vendor/libidn2/config.h +++ b/vendor/libidn2/config.h @@ -429,6 +429,17 @@ /* Define to 1 if you have the `strchrnul' function. */ #define HAVE_STRCHRNUL 1 +/* lib/lookup.c calls strchrnul() but never #include , so it relies + on a declaration being visible by the time it processes config.h. Upstream + gets it from gnulib's substituted ; we don't wire up that overlay + (see build.zig::buildLibidn2). On macOS the symbol is also missing from + libc before 15.4 — build.zig adds vendor/libidn2/darwin/strchrnul.c on + Darwin to satisfy the link. Declare the prototype here so every libidn2 + TU that includes config.h sees a real declaration before preprocessing. */ +#ifdef __APPLE__ +char *strchrnul(const char *s, int c_in); +#endif + /* Define if you have `strerror_r'. */ #define HAVE_STRERROR_R 1 diff --git a/vendor/libidn2/darwin/strchrnul.c b/vendor/libidn2/darwin/strchrnul.c index 04d4836a..3e210e8b 100644 --- a/vendor/libidn2/darwin/strchrnul.c +++ b/vendor/libidn2/darwin/strchrnul.c @@ -1,15 +1,14 @@ -/* macOS libc lacks strchrnul (a glibc extension). libidn2's lib/lookup.c - calls it directly to walk DNS label boundaries. Upstream's portable build - relies on gnulib substituting with a declaration and linking - gl/strchrnul.c, but this build does not wire up that overlay. We provide - a small Darwin-only shim with the same semantics. +/* Darwin-only strchrnul shim for libidn2. - gnulib's strchrnul.c falls through to rawmemchr() when the search byte is - NUL — also a glibc extension. libidn2 only ever searches for '.', so a - straightforward byte scan is sufficient and avoids pulling in a second - shim. */ + strchrnul is a glibc extension. On macOS it is missing from libc before + 15.4 and is never made visible to libidn2's lib/lookup.c (which calls it + without including ). The matching prototype is declared in + vendor/libidn2/config.h under #ifdef __APPLE__, so callers compile; + this file provides the symbol so they link. -#include "strchrnul.h" + gnulib's strchrnul.c falls through to rawmemchr() when the search byte + is NUL — also a glibc extension. libidn2 only ever searches for '.', so + a straight byte scan is enough and avoids dragging in a second shim. */ char *strchrnul(const char *s, int c_in) { const unsigned char c = (unsigned char) c_in; diff --git a/vendor/libidn2/darwin/strchrnul.h b/vendor/libidn2/darwin/strchrnul.h deleted file mode 100644 index 7cc6364f..00000000 --- a/vendor/libidn2/darwin/strchrnul.h +++ /dev/null @@ -1,8 +0,0 @@ -/* Prototype for the macOS strchrnul shim. See strchrnul.c. */ - -#ifndef LPD_LIBIDN2_DARWIN_STRCHRNUL_H -#define LPD_LIBIDN2_DARWIN_STRCHRNUL_H - -char *strchrnul(const char *s, int c_in); - -#endif