diff --git a/apps/chanora_flutter/ios/Flutter/Release.xcconfig b/apps/chanora_flutter/ios/Flutter/Release.xcconfig index f752e6a..ad1f188 100644 --- a/apps/chanora_flutter/ios/Flutter/Release.xcconfig +++ b/apps/chanora_flutter/ios/Flutter/Release.xcconfig @@ -2,10 +2,23 @@ #include "Generated.xcconfig" // Force the linker to retain Swift @_cdecl symbols that the chanora_bridge -// Rust framework resolves at runtime via dlsym(RTLD_DEFAULT). Without these -// flags, Xcode Archive's -dead_strip removes them because no Swift caller -// exists, and CoreML VAD silently falls back to WebRTC on TestFlight/App Store. -OTHER_LDFLAGS = $(inherited) -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_create -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_destroy -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_reset -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_process -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_last_error -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_free_string +// Rust framework resolves at runtime via dlsym(RTLD_DEFAULT). Two flags per +// symbol, intentionally redundant: +// +// -u _sym marks the symbol as force-undefined at link time, +// which keeps the object that defines it from being +// dropped and prevents dead-strip from removing the +// definition. This is the load-bearing flag. +// -exported_symbol _sym re-exports the symbol in the final binary's +// dynamic symbol table so dlsym(RTLD_DEFAULT) can +// find it from the Rust framework at runtime. +// +// Without -u, Xcode Archive's -dead_strip (WMO + LTO) can remove the +// symbol before the export list is applied, and CoreML VAD silently falls +// back to WebRTC on TestFlight / App Store. The Swift-side static +// `unsafeBitCast` references in SileroCoreMLBridge.swift are belt-and- +// suspenders defense-in-depth, NOT the primary guarantee. +OTHER_LDFLAGS = $(inherited) -Xlinker -u -Xlinker _chanora_silero_vad_create -Xlinker -u -Xlinker _chanora_silero_vad_destroy -Xlinker -u -Xlinker _chanora_silero_vad_reset -Xlinker -u -Xlinker _chanora_silero_vad_process -Xlinker -u -Xlinker _chanora_silero_vad_last_error -Xlinker -u -Xlinker _chanora_silero_vad_free_string -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_create -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_destroy -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_reset -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_process -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_last_error -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_free_string // `STRIP_STYLE = all` (Xcode default for archive installs) runs `strip` without // `-x`, which removes even the global @_cdecl symbols the linker exported above diff --git a/apps/chanora_flutter/macos/Flutter/Flutter-Release.xcconfig b/apps/chanora_flutter/macos/Flutter/Flutter-Release.xcconfig index 856b483..6cef814 100644 --- a/apps/chanora_flutter/macos/Flutter/Flutter-Release.xcconfig +++ b/apps/chanora_flutter/macos/Flutter/Flutter-Release.xcconfig @@ -1,11 +1,11 @@ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" -// macOS Release defaults to DEAD_CODE_STRIPPING = YES. Without these flags the -// Swift @_cdecl symbols below would be stripped because no Swift caller exists; -// the chanora_bridge Rust framework resolves them at runtime via -// dlsym(RTLD_DEFAULT) and would silently fall back to WebRTC VAD. -OTHER_LDFLAGS = $(inherited) -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_create -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_destroy -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_reset -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_process -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_last_error -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_free_string +// macOS Release defaults to DEAD_CODE_STRIPPING = YES. See +// ios/Flutter/Release.xcconfig for the full rationale; -u is the +// load-bearing flag, -exported_symbol re-exports for dlsym, both +// are intentionally present per @_cdecl symbol. +OTHER_LDFLAGS = $(inherited) -Xlinker -u -Xlinker _chanora_silero_vad_create -Xlinker -u -Xlinker _chanora_silero_vad_destroy -Xlinker -u -Xlinker _chanora_silero_vad_reset -Xlinker -u -Xlinker _chanora_silero_vad_process -Xlinker -u -Xlinker _chanora_silero_vad_last_error -Xlinker -u -Xlinker _chanora_silero_vad_free_string -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_create -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_destroy -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_reset -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_process -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_last_error -Xlinker -exported_symbol -Xlinker _chanora_silero_vad_free_string // See ios/Flutter/Release.xcconfig for the STRIP_STYLE rationale. STRIP_STYLE = non-global