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.
28 lines
2.2 KiB
Plaintext
28 lines
2.2 KiB
Plaintext
#include? "Pods/Target Support Files/Pods-Chanora/Pods-Chanora.release.xcconfig"
|
|
#include "Generated.xcconfig"
|
|
|
|
// Force the linker to retain Swift @_cdecl symbols that the chanora_bridge
|
|
// 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
|
|
// via -exported_symbol. `non-global` runs `strip -x`, preserving globals so the
|
|
// Rust framework's dlsym(RTLD_DEFAULT) can find them. 264-byte cost in the app.
|
|
STRIP_STYLE = non-global
|