/* eslint-disable @typescript-eslint/no-var-requires */ /** * Workaround für Xcode 16 + RN 0.79 + fmt 11.0.2: * "Call to consteval function 'fmt::basic_format_string<...>' is not a constant expression" * * Grund: fmt/include/fmt/base.h definiert FMT_USE_CONSTEVAL UNCONDITIONAL — * kein `#ifndef`-Guard. Daher hilft `-DFMT_USE_CONSTEVAL=0` als Compiler-Flag * NICHT — fmt's eigener Header überschreibt es. * * Wir patchen daher direkt die Source-Datei nach `pod install`: * - In ios/Pods/fmt/include/fmt/base.h einen Override-Block einfügen, der * nach fmt's eigener Detection FMT_USE_CONSTEVAL auf 0 zwingt. * * Wirkung: * - basic_format_string-Konstruktor ist nicht mehr consteval, sondern constexpr * - FMT_STRING("{}{}") expansion compiliert wieder unter Apple Clang 16+ * * Idempotent — markiert die Patch-Stelle mit einem Magic-Comment. */ const { withDangerousMod } = require('@expo/config-plugins'); const fs = require('fs'); const path = require('path'); const PATCH_MARKER = '/* REBREAK_FMT_CONSTEVAL_FIX */'; const SOURCE_PATCH = ` ${PATCH_MARKER} // Xcode 16 + Apple Clang 16+ haben einen consteval-Bug der fmt's // FMT_STRING-basierte format_to-Calls bricht. Wir zwingen daher // FMT_USE_CONSTEVAL=0 nach fmt's eigener Detection. #undef FMT_USE_CONSTEVAL #define FMT_USE_CONSTEVAL 0 #undef FMT_CONSTEVAL #define FMT_CONSTEVAL #undef FMT_CONSTEXPR20 #define FMT_CONSTEXPR20 ${PATCH_MARKER} `; function patchFmtBaseHeader(podsDir) { const baseHeader = path.join(podsDir, 'fmt', 'include', 'fmt', 'base.h'); if (!fs.existsSync(baseHeader)) { console.warn('[with-fmt-consteval-fix] fmt/base.h not found at', baseHeader); return false; } let content = fs.readFileSync(baseHeader, 'utf-8'); if (content.includes(PATCH_MARKER)) { return false; // schon gepatcht } // Patch nach der Detection-Block einfügen, vor dem `#if FMT_USE_CONSTEVAL` // Suche nach dem End-of-Detection (line endet mit `#endif` direkt vor // `#if FMT_USE_CONSTEVAL`). const anchor = '#if FMT_USE_CONSTEVAL'; const idx = content.indexOf(anchor); if (idx === -1) { console.warn('[with-fmt-consteval-fix] anchor not found in base.h'); return false; } // Patch direkt vor dem anchor einfügen content = content.slice(0, idx) + SOURCE_PATCH + '\n' + content.slice(idx); fs.writeFileSync(baseHeader, content); console.log('[with-fmt-consteval-fix] patched', baseHeader); return true; } module.exports = function withFmtConstevalFix(config) { return withDangerousMod(config, [ 'ios', async (cfg) => { const podsDir = path.join(cfg.modRequest.platformProjectRoot, 'Pods'); // Wenn Pods/ noch nicht existiert (= prebuild Phase, vor pod install): // Patch wird automatisch beim nächsten Run angewendet sobald Pods da sind. // Damit der User aber NICHT manuell nachpatchen muss, packen wir den // Patch zusätzlich in einen Podfile-pre_install-Hook der bei JEDEM // pod install läuft (auch beim ersten). if (fs.existsSync(podsDir)) { patchFmtBaseHeader(podsDir); } // Podfile pre_install-Hook injizieren — patched die fmt-Source bei // jedem pod install (nachdem Pods/fmt/ bereits gedownloaded ist). const podfilePath = path.join(cfg.modRequest.platformProjectRoot, 'Podfile'); let podfile = fs.readFileSync(podfilePath, 'utf-8'); // Alten Patch (frühere Plugin-Version) entfernen const oldPatchRegex = /\s*# ─── Rebreak: fmt consteval fix[\s\S]*?# ───────────────────────────────────────────────────────/g; podfile = podfile.replace(oldPatchRegex, ''); const oldPostInstallPatchRegex = /\s*# ═══ Rebreak: fmt consteval source-patch[\s\S]*?# ═══════════════════════════════════════════════════════/g; podfile = podfile.replace(oldPostInstallPatchRegex, ''); // Neuen pre_install-Hook injizieren (vor `target` block). // Wir patchen die fmt/base.h-Datei direkt im pre_install — pod install // hat dann zu dem Zeitpunkt schon den Pod gedownloaded. const PRE_INSTALL = ` # ═══ Rebreak: fmt consteval source-patch (Xcode 16 + RN 0.79) ═══ pre_install do |installer| fmt_base_h = File.join(installer.sandbox.root, 'fmt', 'include', 'fmt', 'base.h') if File.exist?(fmt_base_h) content = File.read(fmt_base_h) marker = '/* REBREAK_FMT_CONSTEVAL_FIX */' unless content.include?(marker) patch = <<~PATCH #{marker} // Xcode 16 + Apple Clang 16+ consteval-Bug Workaround #undef FMT_USE_CONSTEVAL #define FMT_USE_CONSTEVAL 0 #undef FMT_CONSTEVAL #define FMT_CONSTEVAL #undef FMT_CONSTEXPR20 #define FMT_CONSTEXPR20 #{marker} PATCH anchor = '#if FMT_USE_CONSTEVAL' if content.include?(anchor) content = content.sub(anchor, patch + "\\n" + anchor) File.write(fmt_base_h, content) Pod::UI.puts " -> Patched fmt/base.h with consteval workaround".green end end end end # ═══════════════════════════════════════════════════════ `; // Inject vor dem ersten `target` block (Top-level) const targetMatch = podfile.match(/^target\s+['"][^'"]+['"]\s+do/m); if (targetMatch) { const insertAt = targetMatch.index; podfile = podfile.slice(0, insertAt) + PRE_INSTALL + '\n' + podfile.slice(insertAt); } else { // Fallback: ans Ende anhängen podfile += PRE_INSTALL; } fs.writeFileSync(podfilePath, podfile); return cfg; }, ]); };