diff --git a/apps/mobile/ios/Podfile b/apps/mobile/ios/Podfile index 5e28ff61a..a1cdf9023 100644 --- a/apps/mobile/ios/Podfile +++ b/apps/mobile/ios/Podfile @@ -5,6 +5,8 @@ require Pod::Executable.execute_command('node', ['-p', {paths: [process.argv[1]]}, )', __dir__]).strip +require_relative 'scripts/patch_fmt_consteval' + platform :ios, min_ios_version_supported prepare_react_native_project! @@ -66,6 +68,10 @@ post_install do |installer| :mac_catalyst_enabled => false, # :ccache_enabled => true ) + + # Keep fmt buildable on Xcode >= 26.2. See ios/scripts/patch_fmt_consteval.rb. + PatchFmtConsteval.apply!(installer.sandbox.root) + installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO' diff --git a/apps/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock index 177862349..d576a454d 100644 --- a/apps/mobile/ios/Podfile.lock +++ b/apps/mobile/ios/Podfile.lock @@ -4092,6 +4092,6 @@ SPEC CHECKSUMS: toolbar-android: c426ed5bd3dcccfed20fd79533efc0d1ae0ef018 Yoga: 689c8e04277f3ad631e60fe2a08e41d411daf8eb -PODFILE CHECKSUM: 3fe13efa8356dcc061862bfa9f453dcd12ede70a +PODFILE CHECKSUM: 30b2045c0f4fc91402a43a9e2a872af803f2d6c3 COCOAPODS: 1.16.2 diff --git a/apps/mobile/ios/scripts/patch_fmt_consteval.rb b/apps/mobile/ios/scripts/patch_fmt_consteval.rb new file mode 100644 index 000000000..eb28baf08 --- /dev/null +++ b/apps/mobile/ios/scripts/patch_fmt_consteval.rb @@ -0,0 +1,77 @@ +# Xcode >= 26.2 rejects fmt's compile-time format-string check with +# +# call to consteval function 'fmt::fstring<...>::fstring' is not a +# constant expression +# +# React Native 0.81/0.82 vendor fmt 11.0.2, which hits this. It is an upstream +# incompatibility (reproducible in a stock RN app), but left alone it makes those +# RN versions permanently un-buildable on a modern Xcode. +# +# fmt's own escape hatch is FMT_USE_CONSTEVAL: 0 downgrades the format-string +# check from compile-time to run-time. fmt 11.0.2 does not guard its detection +# block with #ifndef, so we cannot simply predefine the macro -- and doing it +# through the build settings is worse anyway: +# +# * a command-line GCC_PREPROCESSOR_DEFINITIONS outranks every per-target +# value, silently dropping COCOAPODS=1, RCT_METRO_PORT, ... +# * a second `post_install` block in the Podfile REPLACES React Native's own. +# +# So we patch the header itself, right after fmt has made up its mind and before +# the first use of the macro. Idempotent, and safe to run on every pod install. + +module PatchFmtConsteval + MARKER = 'NOTESNOOK_FMT_CONSTEVAL_PATCH'.freeze + + # The line that first consumes the macro; our override goes immediately above + # it, i.e. after the whole detection cascade. + ANCHOR = "#if FMT_USE_CONSTEVAL\n".freeze + + OVERRIDE = <<~PATCH.freeze + // #{MARKER}: Xcode >= 26.2 rejects fmt's consteval format-string check + // (see ios/scripts/patch_fmt_consteval.rb). Applied automatically by + // `pod install`; downgrades the check to run-time. + #undef FMT_USE_CONSTEVAL + #define FMT_USE_CONSTEVAL 0 + PATCH + + # pods_root: the Pods directory (installer.sandbox.root). + def self.apply!(pods_root) + header = File.join(pods_root.to_s, 'fmt', 'include', 'fmt', 'base.h') + + unless File.exist?(header) + Pod::UI.warn "fmt: #{header} not found, skipping consteval patch." + return + end + + contents = File.read(header) + + if contents.include?(MARKER) + Pod::UI.puts 'fmt: consteval patch already applied.' + return + end + + index = contents.index(ANCHOR) + if index.nil? + Pod::UI.warn 'fmt: could not find `#if FMT_USE_CONSTEVAL` in base.h; ' \ + 'the consteval patch was NOT applied. If this fmt version ' \ + 'still uses a consteval format-string check, builds on ' \ + 'Xcode >= 26.2 will fail -- update ' \ + 'ios/scripts/patch_fmt_consteval.rb.' + return + end + + contents.insert(index, OVERRIDE) + + # CocoaPods checks pod sources out read-only (0444), so make the header + # writable for the write and restore the original mode afterwards. + mode = File.stat(header).mode & 0o7777 + begin + File.chmod(mode | 0o200, header) + File.write(header, contents) + ensure + File.chmod(mode, header) + end + + Pod::UI.puts 'fmt: patched base.h to set FMT_USE_CONSTEVAL=0 (Xcode >= 26.2 compatibility).' + end +end