Skip to content

Commit 128a823

Browse files
peachbitsclaude
andcommitted
Vendor the SDK's SwiftPM-only deps as a pre-built static binary
The modern ZcashLightClientKit SDK pulls grpc-swift (1.24+), SwiftNIO, SwiftProtobuf and SQLite.swift via SwiftPM only -- grpc-swift's CocoaPods releases stopped at 1.8.0, so it can no longer be a CocoaPods dependency. Consuming the SDK via spm_dependency would force the entire host app onto dynamic frameworks. Instead, scripts/buildVendoredDeps.ts pre-builds those leaf dependencies into one Release static lib per platform (device arm64; simulator arm64+x86_64, matching the libzcashlc baseline) plus their Swift/C modules, under ios/vendored/ -- generated by 'npm run update-sources' and shipped in the npm tarball. Dependency versions are pinned to the SDK's Package.resolved (-disableAutomaticPackageResolution). The ZcashLightClientKit source keeps compiling in-pod exactly as before, and the host app stays on static frameworks. The binary .swiftmodule format only loads under the exact Swift compiler that produced it (library-evolution .swiftinterface is unavailable: swift-nio doesn't compile under evolution), so the build stamps ios/vendored/swift-version.txt and the podspec fails fast with rebuild instructions when the consuming Xcode doesn't match. Note: sqlite3 is not part of this binary -- SQLite.swift on Apple platforms links the system sqlite3 module, so there is nothing to exclude. Edge's pre-existing duplicate-sqlite3 ld warnings come from libzcashlc vs libpiratelc (both Rust cores embed sqlite3) and are unrelated to this change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2944dd5 commit 128a823

4 files changed

Lines changed: 387 additions & 4 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/android/build/
33
/ios/libzcashlc.xcframework/
44
/ios/ZCashLightClientKit/
5+
/ios/vendored/
56
/ios/zcashlc.h
67
/lib/
78
/tmp/

react-native-zcash.podspec

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,40 @@ require "json"
22

33
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
44

5+
# Each bundled C dep module (ios/vendored/cmodules/<Name>/ — headers +
6+
# module.modulemap) becomes one relative clang include path, so the in-pod
7+
# ZcashLightClientKit source can resolve the C modules that the pre-built Swift
8+
# dependency modules (SwiftNIO / GRPC) import.
9+
cmodule_flags = Dir.glob(File.join(__dir__, "ios/vendored/cmodules/*"))
10+
.select { |p| File.directory?(p) }
11+
.map { |p| "-Xcc -I\"$(PODS_TARGET_SRCROOT)/ios/vendored/cmodules/#{File.basename(p)}\"" }
12+
.join(" ")
13+
14+
# The pre-built Swift modules under ios/vendored/ are only readable by the
15+
# EXACT Swift compiler that produced them (the binary .swiftmodule format is
16+
# not stable across compilers, and the stable alternative — library-evolution
17+
# .swiftinterface — is unavailable because swift-nio rejects evolution builds
18+
# by upstream policy; see apple/swift-nio#2470/#2897, closed "not planned").
19+
# Fail fast with instructions instead of letting the build die later on a
20+
# cryptic "module compiled with Swift X cannot be imported by Swift Y" error.
21+
stamp_path = File.join(__dir__, "ios/vendored/swift-version.txt")
22+
if File.exist?(stamp_path)
23+
built_with = File.read(stamp_path).strip
24+
local_swift = `xcrun swift --version 2>/dev/null`[/swiftlang-[0-9.]+/]
25+
if !built_with.empty? && !local_swift.nil? && built_with != local_swift
26+
raise <<~MSG
27+
react-native-zcash: the prebuilt Swift dependency modules in ios/vendored/
28+
were built with #{built_with}, but this machine's Swift compiler is
29+
#{local_swift}. Binary .swiftmodule files only load under the exact
30+
compiler that produced them.
31+
32+
Fix: rebuild the vendored dependencies with your toolchain:
33+
cd node_modules/react-native-zcash && npm run update-sources
34+
(or switch to the Xcode whose Swift is #{built_with})
35+
MSG
36+
end
37+
end
38+
539
Pod::Spec.new do |s|
640
s.name = package['name']
741
s.version = package['version']
@@ -10,11 +44,15 @@ Pod::Spec.new do |s|
1044
s.license = package['license']
1145
s.authors = package['author']
1246

13-
s.platform = :ios, "13.0"
47+
s.platform = :ios, "16.0"
1448
s.source = {
1549
:git => "https://github.com/EdgeApp/react-native-zcash.git",
1650
:tag => "v#{s.version}"
1751
}
52+
53+
# The bridge + the vendored ZcashLightClientKit Swift source, compiled in-pod
54+
# as ONE module (so the bridge uses SDK types directly — see copySwift in
55+
# scripts/updateSources.ts).
1856
s.source_files =
1957
"ios/react-native-zcash-Bridging-Header.h",
2058
"ios/RNZcash.m",
@@ -25,10 +63,41 @@ Pod::Spec.new do |s|
2563
"zcash-mainnet" => "ios/ZCashLightClientKit/Resources/checkpoints/mainnet/*.json",
2664
"zcash-testnet" => "ios/ZCashLightClientKit/Resources/checkpoints/testnet/*.json"
2765
}
28-
s.vendored_frameworks = "ios/libzcashlc.xcframework"
2966

3067
s.dependency "MnemonicSwift", "~> 2.2"
31-
s.dependency "gRPC-Swift", "~> 1.8"
32-
s.dependency "SQLite.swift/standalone", "~> 0.14"
3368
s.dependency "React-Core"
69+
70+
# The Rust core (a binaryTarget on the SDK's GitHub release):
71+
s.vendored_frameworks = "ios/libzcashlc.xcframework"
72+
73+
# ---------------------------------------------------------------------------
74+
# The SDK's SwiftPM-only dependencies (grpc-swift, SwiftNIO, SwiftProtobuf,
75+
# SQLite.swift) pre-built into one static lib per platform, plus their Swift
76+
# and C modules. grpc-swift 1.24+ ships SwiftPM-only with no podspec, so these
77+
# can no longer be CocoaPods `dependency`s; vendoring them as a static binary
78+
# keeps the host app on STATIC frameworks (consuming the SDK via
79+
# spm_dependency would force the whole app onto dynamic frameworks).
80+
#
81+
# sqlite3 is not in this binary: on Apple platforms SQLite.swift has no C-shim
82+
# target — it imports the system `sqlite3` clang module — so its sqlite3_*
83+
# references resolve at app link time from whatever the host links (in Edge,
84+
# its own sqlite pod and/or the sqlite embedded in libzcashlc). Note: Edge's
85+
# pre-existing duplicate-sqlite3 ld warnings come from libzcashlc vs
86+
# react-native-piratechain's libpiratelc (both Rust cores embed sqlite3) and
87+
# are unrelated to this package's deps binary.
88+
#
89+
# Regenerate ios/vendored/ with `npm run update-sources`
90+
# (scripts/buildVendoredDeps.ts).
91+
# ---------------------------------------------------------------------------
92+
s.preserve_paths = "ios/vendored/**/*"
93+
s.pod_target_xcconfig = {
94+
"SWIFT_INCLUDE_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ios/vendored/modules\"",
95+
"OTHER_SWIFT_FLAGS" => cmodule_flags,
96+
# force_load the matching slice so the deps' Swift type metadata / protocol
97+
# conformances (referenced by the SDK source) aren't dead-stripped:
98+
"OTHER_LDFLAGS[sdk=iphoneos*]" =>
99+
"-force_load \"$(PODS_TARGET_SRCROOT)/ios/vendored/libZcashDeps-ios-arm64.a\"",
100+
"OTHER_LDFLAGS[sdk=iphonesimulator*]" =>
101+
"-force_load \"$(PODS_TARGET_SRCROOT)/ios/vendored/libZcashDeps-ios-arm64-simulator.a\""
102+
}
34103
end

0 commit comments

Comments
 (0)