fix(ios,macos): add -u force-undefined linker flags for @_cdecl symbols
Oracle re-review on PR #26 flagged that the Swift-side `_ = unsafeBitCast(fn as @convention(c) ...)` static references in ChanoraSileroSelfTest.run() are not a robust anti-dead-strip guarantee under WMO + LTO. The optimizer can prove the discarded result has no side effects and eliminate the address-taken reference. The load-bearing fix is a second linker flag per symbol: -u _sym forces the symbol as undefined at link time, preventing the object that defines it from being dropped and stopping -dead_strip from removing the definition. -exported_symbol _sym was already present; re-exports the symbol in the binary's dynamic symbol table so the Rust framework's dlsym(RTLD_DEFAULT) can find it. This flag alone does NOT prevent dead- strip; it only controls the export list applied AFTER dead-strip. Both flags now appear per symbol on both iOS and macOS Release xcconfigs. The Swift-side static references stay as defense-in-depth but are no longer the load-bearing guarantee.
This commit is contained in:
@@ -2,10 +2,23 @@
|
|||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
||||||
// Force the linker to retain Swift @_cdecl symbols that the chanora_bridge
|
// Force the linker to retain Swift @_cdecl symbols that the chanora_bridge
|
||||||
// Rust framework resolves at runtime via dlsym(RTLD_DEFAULT). Without these
|
// Rust framework resolves at runtime via dlsym(RTLD_DEFAULT). Two flags per
|
||||||
// flags, Xcode Archive's -dead_strip removes them because no Swift caller
|
// symbol, intentionally redundant:
|
||||||
// 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
|
// -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
|
// `STRIP_STYLE = all` (Xcode default for archive installs) runs `strip` without
|
||||||
// `-x`, which removes even the global @_cdecl symbols the linker exported above
|
// `-x`, which removes even the global @_cdecl symbols the linker exported above
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|
||||||
// macOS Release defaults to DEAD_CODE_STRIPPING = YES. Without these flags the
|
// macOS Release defaults to DEAD_CODE_STRIPPING = YES. See
|
||||||
// Swift @_cdecl symbols below would be stripped because no Swift caller exists;
|
// ios/Flutter/Release.xcconfig for the full rationale; -u is the
|
||||||
// the chanora_bridge Rust framework resolves them at runtime via
|
// load-bearing flag, -exported_symbol re-exports for dlsym, both
|
||||||
// dlsym(RTLD_DEFAULT) and would silently fall back to WebRTC VAD.
|
// are intentionally present per @_cdecl symbol.
|
||||||
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
|
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.
|
// See ios/Flutter/Release.xcconfig for the STRIP_STYLE rationale.
|
||||||
STRIP_STYLE = non-global
|
STRIP_STYLE = non-global
|
||||||
|
|||||||
Reference in New Issue
Block a user