react-native-cesium 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +12 -0
  3. package/README.md +308 -0
  4. package/ReactNativeCesium.podspec +54 -0
  5. package/android/CMakeLists.txt +146 -0
  6. package/android/build.gradle +178 -0
  7. package/android/fix-prefab.gradle +51 -0
  8. package/android/gradle.properties +5 -0
  9. package/android/src/main/AndroidManifest.xml +5 -0
  10. package/android/src/main/assets/cacert.pem +3529 -0
  11. package/android/src/main/cpp/CesiumBridgeAndroid.cpp +487 -0
  12. package/android/src/main/cpp/CesiumBridgeAndroid.h +94 -0
  13. package/android/src/main/cpp/cpp-adapter.cpp +17 -0
  14. package/android/src/main/cpp/vulkan/VulkanBackend.cpp +1781 -0
  15. package/android/src/main/cpp/vulkan/VulkanBackend.h +190 -0
  16. package/android/src/main/cpp/vulkan/shaders/sky.frag +86 -0
  17. package/android/src/main/cpp/vulkan/shaders/sky.vert +9 -0
  18. package/android/src/main/cpp/vulkan/shaders/terrain.frag +144 -0
  19. package/android/src/main/cpp/vulkan/shaders/terrain.vert +25 -0
  20. package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +84 -0
  21. package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +225 -0
  22. package/android/src/main/java/com/reactnativecesium/ReactNativeCesiumPackage.kt +28 -0
  23. package/cpp/engine/CesiumEngine.cpp +413 -0
  24. package/cpp/engine/CesiumEngine.hpp +90 -0
  25. package/cpp/engine/DeletionQueue.cpp +28 -0
  26. package/cpp/engine/DeletionQueue.hpp +28 -0
  27. package/cpp/engine/GlobeCamera.cpp +181 -0
  28. package/cpp/engine/GlobeCamera.hpp +64 -0
  29. package/cpp/engine/GltfToMesh.cpp +154 -0
  30. package/cpp/engine/GltfToMesh.hpp +20 -0
  31. package/cpp/engine/ResourcePreparer.cpp +224 -0
  32. package/cpp/engine/ResourcePreparer.hpp +96 -0
  33. package/cpp/engine/TaskProcessor.cpp +61 -0
  34. package/cpp/engine/TaskProcessor.hpp +43 -0
  35. package/cpp/engine/TileLifecycleManager.cpp +30 -0
  36. package/cpp/engine/TileLifecycleManager.hpp +25 -0
  37. package/cpp/fmt/format.h +9 -0
  38. package/cpp/renderer/IGPUBackend.hpp +22 -0
  39. package/cpp/renderer/RenderTypes.hpp +112 -0
  40. package/cpp/renderer/ShaderTypes.hpp +29 -0
  41. package/example/README.md +43 -0
  42. package/example/react-native-cesium-example.jpg +0 -0
  43. package/ios/CesiumBridge.h +55 -0
  44. package/ios/CesiumBridge.mm +393 -0
  45. package/ios/HybridCesiumView.swift +299 -0
  46. package/ios/ReactNativeCesium-umbrella.h +16 -0
  47. package/ios/metal/MetalBackend.h +82 -0
  48. package/ios/metal/MetalBackend.mm +839 -0
  49. package/ios/react_native_cesium_ensure_native.rb +12 -0
  50. package/ios/react_native_cesium_post_install.rb +30 -0
  51. package/lib/commonjs/CesiumView.js +13 -0
  52. package/lib/commonjs/CesiumView.js.map +1 -0
  53. package/lib/commonjs/index.js +13 -0
  54. package/lib/commonjs/index.js.map +1 -0
  55. package/lib/commonjs/package.json +1 -0
  56. package/lib/commonjs/specs/cesium-view.nitro.js +6 -0
  57. package/lib/commonjs/specs/cesium-view.nitro.js.map +1 -0
  58. package/lib/module/CesiumView.js +9 -0
  59. package/lib/module/CesiumView.js.map +1 -0
  60. package/lib/module/index.js +4 -0
  61. package/lib/module/index.js.map +1 -0
  62. package/lib/module/specs/cesium-view.nitro.js +4 -0
  63. package/lib/module/specs/cesium-view.nitro.js.map +1 -0
  64. package/lib/typescript/src/CesiumView.d.ts +5 -0
  65. package/lib/typescript/src/CesiumView.d.ts.map +1 -0
  66. package/lib/typescript/src/index.d.ts +3 -0
  67. package/lib/typescript/src/index.d.ts.map +1 -0
  68. package/lib/typescript/src/specs/cesium-view.nitro.d.ts +43 -0
  69. package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -0
  70. package/nitro.json +30 -0
  71. package/nitrogen/generated/.gitattributes +1 -0
  72. package/nitrogen/generated/android/ReactNativeCesium+autolinking.cmake +83 -0
  73. package/nitrogen/generated/android/ReactNativeCesium+autolinking.gradle +27 -0
  74. package/nitrogen/generated/android/ReactNativeCesiumOnLoad.cpp +58 -0
  75. package/nitrogen/generated/android/ReactNativeCesiumOnLoad.hpp +34 -0
  76. package/nitrogen/generated/android/c++/JCameraState.hpp +81 -0
  77. package/nitrogen/generated/android/c++/JCesiumMetrics.hpp +81 -0
  78. package/nitrogen/generated/android/c++/JFunc_void_CesiumMetrics.hpp +78 -0
  79. package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.cpp +178 -0
  80. package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.hpp +83 -0
  81. package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.cpp +92 -0
  82. package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.hpp +49 -0
  83. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CameraState.kt +56 -0
  84. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CesiumMetrics.kt +56 -0
  85. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/Func_void_CesiumMetrics.kt +80 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/HybridCesiumViewSpec.kt +126 -0
  87. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/ReactNativeCesiumOnLoad.kt +35 -0
  88. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewManager.kt +80 -0
  89. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewStateUpdater.kt +23 -0
  90. package/nitrogen/generated/ios/ReactNativeCesium+autolinking.rb +60 -0
  91. package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.cpp +57 -0
  92. package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.hpp +164 -0
  93. package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Umbrella.hpp +53 -0
  94. package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.mm +33 -0
  95. package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.swift +26 -0
  96. package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.cpp +11 -0
  97. package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.hpp +157 -0
  98. package/nitrogen/generated/ios/c++/views/HybridCesiumViewComponent.mm +167 -0
  99. package/nitrogen/generated/ios/swift/CameraState.swift +59 -0
  100. package/nitrogen/generated/ios/swift/CesiumMetrics.swift +59 -0
  101. package/nitrogen/generated/ios/swift/Func_void_CameraState.swift +46 -0
  102. package/nitrogen/generated/ios/swift/Func_void_CesiumMetrics.swift +46 -0
  103. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  104. package/nitrogen/generated/ios/swift/HybridCesiumViewSpec.swift +65 -0
  105. package/nitrogen/generated/ios/swift/HybridCesiumViewSpec_cxx.swift +306 -0
  106. package/nitrogen/generated/shared/c++/CameraState.hpp +107 -0
  107. package/nitrogen/generated/shared/c++/CesiumMetrics.hpp +107 -0
  108. package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.cpp +42 -0
  109. package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.hpp +90 -0
  110. package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.cpp +182 -0
  111. package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.hpp +122 -0
  112. package/nitrogen/generated/shared/json/CesiumViewConfig.json +19 -0
  113. package/package.json +140 -0
  114. package/react-native.config.js +16 -0
  115. package/scripts/cesium/build.mjs +901 -0
  116. package/scripts/cesium/clean.mjs +35 -0
  117. package/scripts/cesium/clone.mjs +32 -0
  118. package/scripts/cesium/ensure-native.mjs +116 -0
  119. package/scripts/cesium/vcpkg-ports/zstd/fix-emscripten-and-clang-cl.patch +31 -0
  120. package/scripts/cesium/vcpkg-ports/zstd/fix-windows-rc-compile.patch +13 -0
  121. package/scripts/cesium/vcpkg-ports/zstd/no-static-suffix.patch +13 -0
  122. package/scripts/cesium/vcpkg-ports/zstd/portfile.cmake +77 -0
  123. package/scripts/cesium/vcpkg-ports/zstd/usage +4 -0
  124. package/scripts/cesium/vcpkg-ports/zstd/vcpkg.json +23 -0
  125. package/scripts/cesium/vcpkg-triplets/arm64-ios-simulator.cmake +10 -0
  126. package/scripts/cesium/vcpkg-triplets/arm64-ios.cmake +14 -0
  127. package/src/CesiumView.tsx +13 -0
  128. package/src/index.ts +7 -0
  129. package/src/specs/cesium-view.nitro.ts +51 -0
@@ -0,0 +1,901 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Release build of Cesium Native for Android (arm64-android) and iOS (arm64-ios + arm64-ios-simulator),
4
+ * then stage under vendor/android and vendor/ios (XCFramework).
5
+ *
6
+ * Prerequisites: CMake 3.15+ (Ninja recommended; otherwise Unix Makefiles on macOS/Linux), git (to auto-clone vcpkg), vcpkg (see resolveVcpkgRoot), Xcode (iOS). Android NDK: ANDROID_NDK_HOME or auto-detect from ANDROID_HOME / ANDROID_SDK_ROOT / ~/Library/Android/sdk/ndk.
7
+ * See README "Maintainers: Cesium Native prebuilts".
8
+ */
9
+ import { execFileSync, spawnSync } from 'node:child_process'
10
+ import {
11
+ cpSync,
12
+ existsSync,
13
+ mkdirSync,
14
+ mkdtempSync,
15
+ readFileSync,
16
+ readdirSync,
17
+ rmSync,
18
+ writeFileSync,
19
+ } from 'node:fs'
20
+ import os from 'node:os'
21
+ import { basename, dirname, join, resolve } from 'node:path'
22
+ import { fileURLToPath } from 'node:url'
23
+
24
+ const __dirname = dirname(fileURLToPath(import.meta.url))
25
+ const root = join(__dirname, '..', '..')
26
+ const cesiumSrc = join(root, 'vendor', 'cesium-native')
27
+ const vendorAndroid = resolve(join(root, 'vendor', 'android'))
28
+ const vendorIos = join(root, 'vendor', 'ios')
29
+ const staging = join(root, 'vendor', '.cesium-staging')
30
+ const stagingDevice = resolve(join(staging, 'ios-device'))
31
+ const stagingSim = resolve(join(staging, 'ios-sim'))
32
+
33
+ const VENDOR_ANDROID_README = `# Android Cesium Native prebuilts
34
+
35
+ This directory is populated by maintainers when running \`yarn run build\` (after
36
+ \`yarn run update\`). It contains a CMake install prefix plus merged
37
+ \`vcpkg_installed/arm64-android\` content so \`find_package(cesium-native)\` works
38
+ without a local vcpkg checkout.
39
+
40
+ Publish this tree with the npm package so consumers do not compile Cesium
41
+ Native themselves.
42
+ `
43
+
44
+ const VENDOR_IOS_README = `# iOS Cesium Native prebuilts
45
+
46
+ This directory is populated by maintainers when running \`yarn run build\` on
47
+ macOS (after \`yarn run update\`). It contains \`CesiumNative.xcframework\` (device
48
+ \`arm64-ios\` and simulator \`arm64-ios-simulator\` slices) produced from merged
49
+ static libraries and shared headers.
50
+
51
+ Publish \`CesiumNative.xcframework\` with the npm package so CocoaPods can link
52
+ without building Cesium Native locally.
53
+ `
54
+
55
+ function run(cmd, args, opts = {}) {
56
+ const r = spawnSync(cmd, args, { stdio: 'inherit', ...opts })
57
+ if (r.status !== 0) {
58
+ process.exit(r.status ?? 1)
59
+ }
60
+ }
61
+
62
+ function hostTriplet() {
63
+ return process.arch === 'arm64' ? 'arm64-osx' : 'x64-osx'
64
+ }
65
+
66
+ function which(bin) {
67
+ try {
68
+ execFileSync('which', [bin], { stdio: 'pipe' })
69
+ return true
70
+ } catch {
71
+ return false
72
+ }
73
+ }
74
+
75
+ /** Absolute path to an executable on PATH, or common install locations (Homebrew). */
76
+ function resolveExecutablePath(name) {
77
+ try {
78
+ const p = execFileSync('/usr/bin/which', [name], { encoding: 'utf8' }).trim()
79
+ if (p && existsSync(p)) return p
80
+ } catch {
81
+ /* ignore */
82
+ }
83
+ for (const dir of ['/opt/homebrew/bin', '/usr/local/bin']) {
84
+ const p = join(dir, name)
85
+ if (existsSync(p)) return p
86
+ }
87
+ return null
88
+ }
89
+
90
+ /**
91
+ * vcpkg spawns nested CMake processes; a minimal PATH (e.g. from GUI / yarn) can hide Homebrew.
92
+ */
93
+ function ensureDarwinBuildPath() {
94
+ if (process.platform !== 'darwin') return
95
+ const extra = ['/opt/homebrew/bin', '/usr/local/bin']
96
+ const cur = process.env.PATH ?? ''
97
+ const seen = new Set(cur.split(':').filter(Boolean))
98
+ const prepend = extra.filter((d) => existsSync(d) && !seen.has(d))
99
+ if (prepend.length === 0) return
100
+ process.env.PATH = [...prepend, ...cur.split(':').filter(Boolean)].join(':')
101
+ console.warn(
102
+ `Prepended to PATH for native builds: ${prepend.join(':')} (so cmake/vcpkg can find ninja, etc.)`
103
+ )
104
+ }
105
+
106
+ /** Prefer Ninja; on macOS require it (vcpkg + iOS builds break with Unix Makefiles when make/clang are not on PATH). */
107
+ let cmakeGenerator = 'Ninja'
108
+
109
+ function resolveCmakeGenerator() {
110
+ if (which('ninja')) {
111
+ cmakeGenerator = 'Ninja'
112
+ return
113
+ }
114
+ if (process.platform === 'darwin') {
115
+ console.error(
116
+ 'ninja is required on macOS for `yarn run build` (vcpkg + Cesium Native). It was not found on PATH.\n' +
117
+ 'Install: brew install ninja\n' +
118
+ 'Then ensure Homebrew is on PATH (Apple Silicon: /opt/homebrew/bin; Intel: /usr/local/bin).'
119
+ )
120
+ process.exit(1)
121
+ }
122
+ if (process.platform === 'linux') {
123
+ cmakeGenerator = 'Unix Makefiles'
124
+ for (const p of ['/usr/bin/gmake', '/usr/bin/make']) {
125
+ if (existsSync(p)) {
126
+ process.env.CMAKE_MAKE_PROGRAM = p
127
+ break
128
+ }
129
+ }
130
+ console.warn(
131
+ 'ninja not found on PATH; using Unix Makefiles' +
132
+ (process.env.CMAKE_MAKE_PROGRAM
133
+ ? ` (CMAKE_MAKE_PROGRAM=${process.env.CMAKE_MAKE_PROGRAM}).`
134
+ : '.') +
135
+ ' For faster builds: apt install ninja-build (or equivalent).'
136
+ )
137
+ return
138
+ }
139
+ console.error(
140
+ 'ninja must be on PATH for CMake on this OS. Install Ninja: https://ninja-build.org/'
141
+ )
142
+ process.exit(1)
143
+ }
144
+
145
+ /**
146
+ * GUI-launched terminals sometimes have a minimal PATH; vcpkg/Cmake then fail with
147
+ * CMAKE_C_COMPILER not set. Pin host CC/CXX to Xcode clang when unset.
148
+ */
149
+ function ensureDarwinClangEnv() {
150
+ if (process.platform !== 'darwin') return
151
+ try {
152
+ const cc = execFileSync('xcrun', ['--find', 'clang'], { encoding: 'utf8' }).trim()
153
+ const cxx = execFileSync('xcrun', ['--find', 'clang++'], { encoding: 'utf8' }).trim()
154
+ if (!cc || !cxx) {
155
+ throw new Error('xcrun returned empty compiler path')
156
+ }
157
+ if (!process.env.CC) process.env.CC = cc
158
+ if (!process.env.CXX) process.env.CXX = cxx
159
+ } catch {
160
+ console.error(
161
+ 'Could not locate Apple clang via xcrun. Install Xcode or the Command Line Tools:\n' +
162
+ ' xcode-select --install\n' +
163
+ 'If Xcode is installed: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer'
164
+ )
165
+ process.exit(1)
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Host vcpkg ports (e.g. openssl for arm64-osx) need the macOS SDK; without SDKROOT, clang
171
+ * may not resolve system headers (stdlib.h, assert.h). EZVCPKG-driven CMake hits this with a
172
+ * minimal environment.
173
+ */
174
+ function ensureDarwinSdkRoot() {
175
+ if (process.platform !== 'darwin') return
176
+ if (process.env.SDKROOT?.trim()) return
177
+ try {
178
+ const sdk = execFileSync('xcrun', ['--sdk', 'macosx', '--show-sdk-path'], {
179
+ encoding: 'utf8',
180
+ }).trim()
181
+ if (sdk) {
182
+ process.env.SDKROOT = sdk
183
+ }
184
+ } catch {
185
+ console.warn(
186
+ 'Could not run `xcrun --sdk macosx --show-sdk-path`. If native builds fail with missing system headers, install Xcode or CLT and set:\n' +
187
+ ' export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)'
188
+ )
189
+ }
190
+ }
191
+
192
+ /** Ninja must be an absolute path for nested vcpkg CMake configures (same as CC/CXX). */
193
+ function ensureNinjaMakeProgram() {
194
+ if (cmakeGenerator !== 'Ninja') return
195
+ const existing = process.env.CMAKE_MAKE_PROGRAM?.trim()
196
+ if (existing && existsSync(existing)) return
197
+ const ninja = resolveExecutablePath('ninja')
198
+ if (!ninja) {
199
+ console.error(
200
+ 'Could not resolve ninja to an absolute path. Install: brew install ninja\n' +
201
+ 'Ensure /opt/homebrew/bin or /usr/local/bin is on PATH.'
202
+ )
203
+ process.exit(1)
204
+ }
205
+ process.env.CMAKE_MAKE_PROGRAM = ninja
206
+ }
207
+
208
+ function isValidVcpkgRoot(dir) {
209
+ return existsSync(join(dir, 'scripts', 'buildsystems', 'vcpkg.cmake'))
210
+ }
211
+
212
+ /** Normalize a path from .vcpkg-root: ~ expansion, or relative to repo root. */
213
+ function normalizeVcpkgCandidate(raw) {
214
+ const v = raw.trim()
215
+ if (!v || v.startsWith('#')) return null
216
+ if (v.startsWith('~')) {
217
+ return join(os.homedir(), v.slice(1).replace(/^\//, ''))
218
+ }
219
+ if (v.startsWith('/') || /^[A-Za-z]:[\\/]/.test(v)) {
220
+ return v
221
+ }
222
+ return join(root, v)
223
+ }
224
+
225
+ /**
226
+ * Sets process.env.VCPKG_ROOT. Order: env var, .vcpkg-root file, ~/vcpkg, vendor/vcpkg,
227
+ * else clone+bootstrap into vendor/vcpkg (unless CESIUM_SKIP_AUTO_VCPKG=1).
228
+ */
229
+ function resolveVcpkgRoot() {
230
+ const env = process.env.VCPKG_ROOT?.trim()
231
+ if (env) {
232
+ if (isValidVcpkgRoot(env)) {
233
+ process.env.VCPKG_ROOT = env
234
+ return
235
+ }
236
+ console.error(
237
+ `VCPKG_ROOT="${env}" does not contain scripts/buildsystems/vcpkg.cmake.\n` +
238
+ 'Clone and bootstrap vcpkg: https://github.com/microsoft/vcpkg'
239
+ )
240
+ process.exit(1)
241
+ }
242
+
243
+ const dotfile = join(root, '.vcpkg-root')
244
+ if (existsSync(dotfile)) {
245
+ const line = readFileSync(dotfile, 'utf8')
246
+ .split(/\r?\n/)
247
+ .map((l) => l.trim())
248
+ .find((l) => l && !l.startsWith('#'))
249
+ if (line) {
250
+ const p = normalizeVcpkgCandidate(line)
251
+ if (p && isValidVcpkgRoot(p)) {
252
+ process.env.VCPKG_ROOT = p
253
+ console.warn(`Using VCPKG_ROOT from .vcpkg-root: ${p}`)
254
+ return
255
+ }
256
+ }
257
+ }
258
+
259
+ const homeVcpkg = join(os.homedir(), 'vcpkg')
260
+ if (isValidVcpkgRoot(homeVcpkg)) {
261
+ process.env.VCPKG_ROOT = homeVcpkg
262
+ console.warn(
263
+ `Using VCPKG_ROOT=${homeVcpkg} (auto-detected). Set VCPKG_ROOT or add .vcpkg-root to override.`
264
+ )
265
+ return
266
+ }
267
+
268
+ const vendorVcpkg = join(root, 'vendor', 'vcpkg')
269
+ if (isValidVcpkgRoot(vendorVcpkg)) {
270
+ process.env.VCPKG_ROOT = vendorVcpkg
271
+ console.warn(`Using VCPKG_ROOT=${vendorVcpkg} (auto-detected).`)
272
+ return
273
+ }
274
+
275
+ if (process.env.CESIUM_SKIP_AUTO_VCPKG === '1') {
276
+ printVcpkgMissingHelp()
277
+ process.exit(1)
278
+ }
279
+
280
+ cloneAndBootstrapVendorVcpkg(vendorVcpkg)
281
+ process.env.VCPKG_ROOT = vendorVcpkg
282
+ }
283
+
284
+ function printVcpkgMissingHelp() {
285
+ console.error(`No vcpkg installation found.
286
+
287
+ Set one of:
288
+ export VCPKG_ROOT=/path/to/vcpkg
289
+ Or create a gitignored file in the repo root (first line = path):
290
+ echo /path/to/vcpkg > .vcpkg-root
291
+
292
+ Or remove CESIUM_SKIP_AUTO_VCPKG to let the build clone vcpkg into vendor/vcpkg.
293
+
294
+ Manual install (from Cesium Native developer setup):
295
+ git clone https://github.com/microsoft/vcpkg.git "$HOME/vcpkg"
296
+ cd "$HOME/vcpkg" && ./bootstrap-vcpkg.sh
297
+
298
+ https://github.com/CesiumGS/cesium-native/blob/main/doc/topics/developer-setup.md
299
+ `)
300
+ }
301
+
302
+ /**
303
+ * Clone microsoft/vcpkg into vendor/vcpkg and run bootstrap (gitignored, not committed).
304
+ */
305
+ function cloneAndBootstrapVendorVcpkg(vendorVcpkg) {
306
+ if (!which('git')) {
307
+ console.error('git is required on PATH to clone vcpkg, or set VCPKG_ROOT to an existing install.')
308
+ printVcpkgMissingHelp()
309
+ process.exit(1)
310
+ }
311
+
312
+ console.warn(
313
+ 'Cloning and bootstrapping vcpkg into vendor/vcpkg (first run; large download, several minutes)...'
314
+ )
315
+ mkdirSync(join(root, 'vendor'), { recursive: true })
316
+
317
+ if (existsSync(vendorVcpkg)) {
318
+ rmSync(vendorVcpkg, { recursive: true, force: true })
319
+ }
320
+
321
+ run('git', [
322
+ 'clone',
323
+ '--depth',
324
+ '1',
325
+ 'https://github.com/microsoft/vcpkg.git',
326
+ vendorVcpkg,
327
+ ])
328
+
329
+ if (process.platform === 'win32') {
330
+ run('cmd', ['/c', 'bootstrap-vcpkg.bat'], { cwd: vendorVcpkg, env: process.env })
331
+ } else {
332
+ run('sh', ['bootstrap-vcpkg.sh'], { cwd: vendorVcpkg, env: process.env })
333
+ }
334
+
335
+ if (!isValidVcpkgRoot(vendorVcpkg)) {
336
+ console.error(
337
+ 'bootstrap-vcpkg did not produce scripts/buildsystems/vcpkg.cmake. See output above.'
338
+ )
339
+ process.exit(1)
340
+ }
341
+
342
+ console.warn(`VCPKG_ROOT=${vendorVcpkg} (vendor clone + bootstrap complete)`)
343
+ }
344
+
345
+ function mergeStaticLibs(libDir, outFile) {
346
+ const libs = []
347
+ function walk(d) {
348
+ for (const name of readdirSync(d, { withFileTypes: true })) {
349
+ const p = join(d, name.name)
350
+ if (name.isDirectory()) walk(p)
351
+ else if (name.name.endsWith('.a')) libs.push(p)
352
+ }
353
+ }
354
+ walk(libDir)
355
+ if (libs.length === 0) {
356
+ throw new Error(`No .a files under ${libDir}`)
357
+ }
358
+ run('libtool', ['-static', '-o', outFile, ...libs])
359
+ }
360
+
361
+ function rsyncMerge(src, dst) {
362
+ if (!existsSync(src)) {
363
+ throw new Error(`Expected path missing: ${src}`)
364
+ }
365
+ cpSync(src, dst, { recursive: true })
366
+ }
367
+
368
+ /**
369
+ * Stale CMakeCache from a previous generator (e.g. Unix Makefiles before we required Ninja
370
+ * on macOS) makes CMake abort with "Does not match the generator used previously".
371
+ */
372
+ function normalizePathKey(p) {
373
+ return p.replace(/\/+$/, '')
374
+ }
375
+
376
+ /**
377
+ * cesium-native installs headers with `install(DIRECTORY ... DESTINATION \${CMAKE_INSTALL_PREFIX})`,
378
+ * so the prefix is frozen at configure time. A stale cache (e.g. /usr/local) breaks install.
379
+ * CMake may store CMAKE_INSTALL_PREFIX as PATH, STRING, etc. — match any cache line type.
380
+ */
381
+ function ensureCmakeInstallPrefixCache(buildDir, expectedPrefix) {
382
+ const cacheFile = join(buildDir, 'CMakeCache.txt')
383
+ if (!existsSync(cacheFile)) return
384
+ const expected = normalizePathKey(resolve(expectedPrefix))
385
+ let text
386
+ try {
387
+ text = readFileSync(cacheFile, 'utf8')
388
+ } catch {
389
+ return
390
+ }
391
+ const m = text.match(/^CMAKE_INSTALL_PREFIX:[A-Za-z0-9_]+=(.*)$/m)
392
+ if (!m) return
393
+ const raw = m[1].trim()
394
+ if (raw === '') return
395
+ const cached = normalizePathKey(resolve(raw))
396
+ if (cached === expected) return
397
+ console.warn(
398
+ `Removing ${buildDir} (CMake cache CMAKE_INSTALL_PREFIX was:\n ${cached}\nexpected:\n ${expected}\nCesium Native bakes the prefix into install rules; it must match before configure.)`
399
+ )
400
+ rmSync(buildDir, { recursive: true, force: true })
401
+ }
402
+
403
+ function parseCmakeInstallPrefixFromArgs(extraArgs) {
404
+ const p = '-DCMAKE_INSTALL_PREFIX='
405
+ for (const a of extraArgs) {
406
+ if (typeof a === 'string' && a.startsWith(p)) {
407
+ return resolve(a.slice(p.length))
408
+ }
409
+ }
410
+ return null
411
+ }
412
+
413
+ /**
414
+ * Old cesium-native caches can still point at ezvcpkg (~/.ezvcpkg) host artifacts
415
+ * like arm64-osx even when this script now configures manifest-mode Android/iOS builds.
416
+ * If so, generated install rules and dependency paths are irreparably wrong; wipe the tree.
417
+ */
418
+ function ensureNoEzvcpkgCache(buildDir) {
419
+ const cacheFile = join(buildDir, 'CMakeCache.txt')
420
+ if (!existsSync(cacheFile)) return
421
+ let text
422
+ try {
423
+ text = readFileSync(cacheFile, 'utf8')
424
+ } catch {
425
+ return
426
+ }
427
+ if (!text.includes('.ezvcpkg')) return
428
+ console.warn(
429
+ `Removing ${buildDir} (stale cache still references ~/.ezvcpkg host packages; this build must use manifest-mode vcpkg under the build directory).`
430
+ )
431
+ rmSync(buildDir, { recursive: true, force: true })
432
+ }
433
+
434
+ /**
435
+ * Manifest-mode vcpkg installs under ${buildDir}/vcpkg_installed. If an old cache pointed
436
+ * VCPKG_INSTALLED_DIR at $VCPKG_ROOT/installed (or anything else), cesium-native sets
437
+ * PACKAGE_BUILD_DIR wrong and find_package(modp_b64) etc. fail.
438
+ */
439
+ function ensureVcpkgInstalledDirCache(buildDir) {
440
+ const cacheFile = join(buildDir, 'CMakeCache.txt')
441
+ if (!existsSync(cacheFile)) return
442
+ const expected = normalizePathKey(join(buildDir, 'vcpkg_installed'))
443
+ let text
444
+ try {
445
+ text = readFileSync(cacheFile, 'utf8')
446
+ } catch {
447
+ return
448
+ }
449
+ const m = text.match(/^VCPKG_INSTALLED_DIR:PATH=(.+)$/m)
450
+ if (!m) return
451
+ const cached = normalizePathKey(m[1].trim())
452
+ if (cached === expected) return
453
+ console.warn(
454
+ `Removing ${buildDir} (CMake cache VCPKG_INSTALLED_DIR was:\n ${cached}\nexpected:\n ${expected}\nClearing so vcpkg manifest installs land under the build directory.)`
455
+ )
456
+ rmSync(buildDir, { recursive: true, force: true })
457
+ }
458
+
459
+ function ensureCmakeBuildDirGenerator(buildDir) {
460
+ const cacheFile = join(buildDir, 'CMakeCache.txt')
461
+ if (!existsSync(cacheFile)) return
462
+ let text
463
+ try {
464
+ text = readFileSync(cacheFile, 'utf8')
465
+ } catch {
466
+ return
467
+ }
468
+ const m = text.match(/^CMAKE_GENERATOR:INTERNAL=(.+)$/m)
469
+ const prev = m?.[1]?.trim()
470
+ if (!prev || prev === cmakeGenerator) return
471
+ console.warn(
472
+ `Removing ${buildDir} (previous CMake generator was "${prev}"; this run uses "${cmakeGenerator}").`
473
+ )
474
+ rmSync(buildDir, { recursive: true, force: true })
475
+ }
476
+
477
+ /**
478
+ * Overlay ports (e.g. zstd without pthreads on iOS — see scripts/cesium/vcpkg-ports).
479
+ * Prepended so they override the registry; Cesium Native also uses ./extern/vcpkg/ports.
480
+ */
481
+ function ensureVcpkgOverlayPorts() {
482
+ const overlayPorts = resolve(join(__dirname, 'vcpkg-ports'))
483
+ if (!existsSync(overlayPorts)) return
484
+ const sep = process.platform === 'win32' ? ';' : ':'
485
+ const parts = (process.env.VCPKG_OVERLAY_PORTS ?? '').split(sep).filter(Boolean)
486
+ if (!parts.includes(overlayPorts)) {
487
+ parts.unshift(overlayPorts)
488
+ }
489
+ process.env.VCPKG_OVERLAY_PORTS = parts.join(sep)
490
+ }
491
+
492
+ /**
493
+ * iOS vcpkg overlay + env fallback for CMake configure options that ports need:
494
+ * - HAVE_PIPE2=OFF (curl; iOS has no pipe2)
495
+ * - CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY (FindThreads / zstd → ktx; executable
496
+ * try_compile often fails for iphoneOS targets)
497
+ *
498
+ * Triplet files under scripts/cesium/vcpkg-triplets/ are authoritative; env is a fallback.
499
+ */
500
+ function ensureIosVcpkgTripletOverlay() {
501
+ const overlay = resolve(join(__dirname, 'vcpkg-triplets'))
502
+ if (!existsSync(overlay)) return
503
+ const sep = process.platform === 'win32' ? ';' : ':'
504
+ const parts = (process.env.VCPKG_OVERLAY_TRIPLETS ?? '')
505
+ .split(sep)
506
+ .filter(Boolean)
507
+ if (!parts.includes(overlay)) {
508
+ parts.unshift(overlay)
509
+ }
510
+ process.env.VCPKG_OVERLAY_TRIPLETS = parts.join(sep)
511
+ }
512
+
513
+ function ensureIosVcpkgPortOptions(extraArgs) {
514
+ const isIos = extraArgs.some(
515
+ (a) =>
516
+ a.includes('CMAKE_SYSTEM_NAME=iOS') ||
517
+ a.includes('iphoneos') ||
518
+ a.includes('iphonesimulator')
519
+ )
520
+ if (!isIos) return
521
+ ensureIosVcpkgTripletOverlay()
522
+ let cur = process.env.VCPKG_CMAKE_CONFIGURE_OPTIONS?.trim() ?? ''
523
+ if (!cur.includes('HAVE_PIPE2')) {
524
+ cur = cur ? `${cur};-DHAVE_PIPE2=OFF` : '-DHAVE_PIPE2=OFF'
525
+ }
526
+ if (!cur.includes('CMAKE_TRY_COMPILE_TARGET_TYPE')) {
527
+ cur = cur
528
+ ? `${cur};-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY`
529
+ : '-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY'
530
+ }
531
+ process.env.VCPKG_CMAKE_CONFIGURE_OPTIONS = cur
532
+ }
533
+
534
+ function cmakeConfigure(buildDir, extraArgs) {
535
+ ensureVcpkgOverlayPorts()
536
+ const installPrefix = parseCmakeInstallPrefixFromArgs(extraArgs)
537
+ if (installPrefix) {
538
+ ensureCmakeInstallPrefixCache(buildDir, installPrefix)
539
+ }
540
+ ensureNoEzvcpkgCache(buildDir)
541
+ ensureVcpkgInstalledDirCache(buildDir)
542
+ ensureCmakeBuildDirGenerator(buildDir)
543
+ ensureIosVcpkgPortOptions(extraArgs)
544
+ const vcpkgInstalledDir = join(buildDir, 'vcpkg_installed')
545
+ const toolchainArgs = [`-DVCPKG_INSTALLED_DIR=${vcpkgInstalledDir}`]
546
+ if (cmakeGenerator === 'Ninja' && process.env.CMAKE_MAKE_PROGRAM) {
547
+ toolchainArgs.push(`-DCMAKE_MAKE_PROGRAM=${process.env.CMAKE_MAKE_PROGRAM}`)
548
+ }
549
+ if (process.platform === 'darwin' && process.env.CC && process.env.CXX) {
550
+ toolchainArgs.push(
551
+ `-DCMAKE_C_COMPILER=${process.env.CC}`,
552
+ `-DCMAKE_CXX_COMPILER=${process.env.CXX}`
553
+ )
554
+ }
555
+ const args = [
556
+ '-S',
557
+ cesiumSrc,
558
+ '-B',
559
+ buildDir,
560
+ '-G',
561
+ cmakeGenerator,
562
+ '-DCMAKE_BUILD_TYPE=Release',
563
+ `-DCMAKE_TOOLCHAIN_FILE=${join(process.env.VCPKG_ROOT, 'scripts', 'buildsystems', 'vcpkg.cmake')}`,
564
+ '-DCESIUM_USE_EZVCPKG=OFF',
565
+ '-DCESIUM_TESTS_ENABLED=OFF',
566
+ '-DCESIUM_ENABLE_CLANG_TIDY=OFF',
567
+ `-DVCPKG_HOST_TRIPLET=${hostTriplet()}`,
568
+ ...toolchainArgs,
569
+ ...extraArgs,
570
+ ]
571
+ // Last flag wins: vcpkg / chainloaded toolchains must not leave CMAKE_INSTALL_PREFIX at /usr/local.
572
+ if (installPrefix) {
573
+ args.push(`-DCMAKE_INSTALL_PREFIX:PATH=${installPrefix}`)
574
+ }
575
+ run('cmake', args, { cwd: root, env: process.env })
576
+ }
577
+
578
+ function cmakeBuildInstall(buildDir, installPrefix) {
579
+ const jobs =
580
+ process.env.CESIUM_BUILD_JOBS && /^\d+$/.test(process.env.CESIUM_BUILD_JOBS)
581
+ ? process.env.CESIUM_BUILD_JOBS
582
+ : String(Math.max(1, os.cpus().length))
583
+ run('cmake', ['--build', buildDir, '--parallel', jobs], { cwd: root, env: process.env })
584
+ rmSync(installPrefix, { recursive: true, force: true })
585
+ mkdirSync(installPrefix, { recursive: true })
586
+ run('cmake', ['--install', buildDir, '--prefix', installPrefix], { cwd: root, env: process.env })
587
+ }
588
+
589
+ function mergeVcpkgInstalled(buildDir, triplet, installPrefix) {
590
+ const vp = join(buildDir, 'vcpkg_installed', triplet)
591
+ if (!existsSync(vp)) {
592
+ throw new Error(`vcpkg_installed not found: ${vp}`)
593
+ }
594
+ rsyncMerge(vp, installPrefix)
595
+ }
596
+
597
+ function assertFile(p) {
598
+ if (!existsSync(p)) {
599
+ throw new Error(`Expected file missing: ${p}`)
600
+ }
601
+ }
602
+
603
+ /**
604
+ * Ensure Android static libs contain ELF objects (not Mach-O from a mistaken iOS/host build).
605
+ */
606
+ function firstObjectFileUnder(dir) {
607
+ const stack = [dir]
608
+ while (stack.length) {
609
+ const d = stack.pop()
610
+ for (const e of readdirSync(d, { withFileTypes: true })) {
611
+ const p = join(d, e.name)
612
+ if (e.isDirectory()) stack.push(p)
613
+ else if (e.name.endsWith('.o')) return p
614
+ }
615
+ }
616
+ return null
617
+ }
618
+
619
+ function assertAndroidPrebuiltsAreElf() {
620
+ const lib = join(vendorAndroid, 'lib', 'libCesiumUtility.a')
621
+ if (!existsSync(lib)) return
622
+ const arBin = resolveAndroidLlvmAr()
623
+ if (!arBin) {
624
+ throw new Error(
625
+ 'Cannot verify Android prebuilts: no llvm-ar under ANDROID_NDK_HOME (use NDK llvm-ar, not system ar).'
626
+ )
627
+ }
628
+ const tmp = mkdtempSync(join(os.tmpdir(), 'rn-cesium-android-elf-'))
629
+ try {
630
+ const listOut = execFileSync(arBin, ['t', lib], { encoding: 'utf8' })
631
+ const member = listOut
632
+ .split(/\r?\n/)
633
+ .map((l) => l.trim())
634
+ .find((l) => l.endsWith('.o'))
635
+ if (!member) return
636
+ execFileSync(arBin, ['x', lib, member], { cwd: tmp })
637
+ const target = firstObjectFileUnder(tmp)
638
+ if (!target) return
639
+ const out = execFileSync('file', [target], { encoding: 'utf8' })
640
+ if (out.includes('Mach-O')) {
641
+ throw new Error(
642
+ 'Android prebuilts in vendor/android contain Mach-O objects (Apple), not ELF. ' +
643
+ 'Remove vendor/android and run CESIUM_BUILD_ONLY=android yarn build with a proper Android NDK (arm64-android).'
644
+ )
645
+ }
646
+ if (!out.includes('ELF')) {
647
+ console.warn(`Unexpected object type from ${lib} (first member): ${out.trim()}`)
648
+ }
649
+ } finally {
650
+ rmSync(tmp, { recursive: true, force: true })
651
+ }
652
+ }
653
+
654
+ function isValidNdkRoot(dir) {
655
+ return existsSync(join(dir, 'build', 'cmake', 'android.toolchain.cmake'))
656
+ }
657
+
658
+ /** Prefer newer NDK folders (e.g. 27.1.12297006). */
659
+ function compareNdkVersionDesc(a, b) {
660
+ const pa = a.split('.').map((x) => parseInt(x, 10) || 0)
661
+ const pb = b.split('.').map((x) => parseInt(x, 10) || 0)
662
+ const n = Math.max(pa.length, pb.length)
663
+ for (let i = 0; i < n; i++) {
664
+ const da = pa[i] ?? 0
665
+ const db = pb[i] ?? 0
666
+ if (da !== db) return db - da
667
+ }
668
+ return 0
669
+ }
670
+
671
+ function pickLatestNdkUnder(ndkParentDir) {
672
+ let dirs = []
673
+ try {
674
+ dirs = readdirSync(ndkParentDir, { withFileTypes: true })
675
+ .filter((d) => d.isDirectory())
676
+ .map((d) => join(ndkParentDir, d.name))
677
+ } catch {
678
+ return null
679
+ }
680
+ const valid = dirs.filter((d) => isValidNdkRoot(d))
681
+ if (valid.length === 0) return null
682
+ valid.sort((x, y) => compareNdkVersionDesc(basename(x), basename(y)))
683
+ return valid[0]
684
+ }
685
+
686
+ /**
687
+ * Sets process.env.ANDROID_NDK_HOME. Uses env var, or scans SDK ndk/ for versioned folders.
688
+ */
689
+ function resolveAndroidNdkHome() {
690
+ const env = process.env.ANDROID_NDK_HOME?.trim()
691
+ if (env) {
692
+ if (isValidNdkRoot(env)) {
693
+ process.env.ANDROID_NDK_HOME = env
694
+ return env
695
+ }
696
+ console.error(
697
+ `ANDROID_NDK_HOME="${env}" is not a valid NDK root (missing build/cmake/android.toolchain.cmake).`
698
+ )
699
+ process.exit(1)
700
+ }
701
+
702
+ const sdkCandidates = [
703
+ process.env.ANDROID_HOME?.trim(),
704
+ process.env.ANDROID_SDK_ROOT?.trim(),
705
+ join(os.homedir(), 'Library', 'Android', 'sdk'),
706
+ join(os.homedir(), 'Android', 'Sdk'),
707
+ ].filter(Boolean)
708
+
709
+ for (const sdk of sdkCandidates) {
710
+ if (!existsSync(sdk)) continue
711
+ const ndkParent = join(sdk, 'ndk')
712
+ const picked = pickLatestNdkUnder(ndkParent)
713
+ if (picked) {
714
+ process.env.ANDROID_NDK_HOME = picked
715
+ console.warn(
716
+ `Using ANDROID_NDK_HOME=${picked} (auto-detected). Override with ANDROID_NDK_HOME if needed.`
717
+ )
718
+ return picked
719
+ }
720
+ }
721
+
722
+ console.error(`Could not find Android NDK.
723
+
724
+ Install the NDK (Android Studio → Settings → SDK → SDK Tools → NDK),
725
+ or set:
726
+ export ANDROID_NDK_HOME=/path/to/ndk/27.x.x
727
+
728
+ Or build only iOS (macOS):
729
+ CESIUM_BUILD_ONLY=ios yarn build
730
+ `)
731
+ process.exit(1)
732
+ }
733
+
734
+ /**
735
+ * Path to NDK llvm-ar. macOS system `ar` is BSD and cannot list/extract GNU thin archives
736
+ * produced by the Android toolchain (see `ar t` noise like `/`, `Assert.cpp.o/`).
737
+ */
738
+ function resolveAndroidLlvmAr() {
739
+ const ndk = process.env.ANDROID_NDK_HOME?.trim()
740
+ if (!ndk) return null
741
+ const prebuilt = join(ndk, 'toolchains', 'llvm', 'prebuilt')
742
+ if (!existsSync(prebuilt)) return null
743
+ for (const host of readdirSync(prebuilt)) {
744
+ const base = join(prebuilt, host)
745
+ for (const rel of ['bin/llvm-ar', 'llvm-ar']) {
746
+ const p = join(base, ...rel.split('/'))
747
+ if (existsSync(p)) return p
748
+ }
749
+ }
750
+ return null
751
+ }
752
+
753
+ function buildAndroid() {
754
+ const ndk = resolveAndroidNdkHome()
755
+ const triplet = 'arm64-android'
756
+ const buildDir = join(cesiumSrc, 'build-android-arm64')
757
+ process.env.ANDROID_NDK_HOME = ndk
758
+
759
+ const ndkToolchain = join(ndk, 'build', 'cmake', 'android.toolchain.cmake')
760
+ if (!existsSync(ndkToolchain)) {
761
+ throw new Error(`Missing NDK CMake toolchain: ${ndkToolchain}`)
762
+ }
763
+ // Cesium Native bakes absolute install destinations into generated install scripts.
764
+ // Reusing build-android-arm64 has repeatedly preserved stale /usr/local and ezvcpkg-host paths,
765
+ // even after we added cache guards. A clean Android configure is slower but consistent.
766
+ rmSync(buildDir, { recursive: true, force: true })
767
+ // Required so vcpkg + dependencies compile with the NDK (ELF aarch64), not host Clang (Mach-O on macOS).
768
+ cmakeConfigure(buildDir, [
769
+ `-DCMAKE_INSTALL_PREFIX=${vendorAndroid}`,
770
+ `-DVCPKG_TARGET_TRIPLET=${triplet}`,
771
+ `-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=${ndkToolchain}`,
772
+ `-DCMAKE_ANDROID_NDK=${ndk}`,
773
+ '-DANDROID_ABI=arm64-v8a',
774
+ '-DANDROID_PLATFORM=android-24',
775
+ ])
776
+ cmakeBuildInstall(buildDir, vendorAndroid)
777
+ mergeVcpkgInstalled(buildDir, triplet, vendorAndroid)
778
+ assertFile(join(vendorAndroid, 'share', 'cesium-native', 'cmake', 'cesium-nativeConfig.cmake'))
779
+ assertAndroidPrebuiltsAreElf()
780
+ writeFileSync(join(vendorAndroid, 'README.md'), VENDOR_ANDROID_README)
781
+ console.log(`Android prebuilts staged under ${vendorAndroid}`)
782
+ }
783
+
784
+ function buildIosDevice() {
785
+ const triplet = 'arm64-ios'
786
+ const buildDir = join(cesiumSrc, 'build-ios-device')
787
+ cmakeConfigure(buildDir, [
788
+ `-DCMAKE_INSTALL_PREFIX=${stagingDevice}`,
789
+ `-DVCPKG_TARGET_TRIPLET=${triplet}`,
790
+ '-DCMAKE_SYSTEM_NAME=iOS',
791
+ '-DCMAKE_OSX_SYSROOT=iphoneos',
792
+ '-DCMAKE_OSX_ARCHITECTURES=arm64',
793
+ '-DCMAKE_OSX_DEPLOYMENT_TARGET=15.1',
794
+ // Xcode 16 may inject -ffp-model=precise while cesium-native sets -ffp-contract=off.
795
+ // Keep the diagnostic visible, but avoid failing the whole prebuilt pipeline on this override.
796
+ '-DCMAKE_CXX_FLAGS=-Wno-error=overriding-option',
797
+ ])
798
+ cmakeBuildInstall(buildDir, stagingDevice)
799
+ mergeVcpkgInstalled(buildDir, triplet, stagingDevice)
800
+ assertFile(join(stagingDevice, 'share', 'cesium-native', 'cmake', 'cesium-nativeConfig.cmake'))
801
+ const merged = join(stagingDevice, 'libCesiumNativePrebuilt.a')
802
+ mergeStaticLibs(join(stagingDevice, 'lib'), merged)
803
+ console.log(`iOS device staging + merged static lib: ${merged}`)
804
+ }
805
+
806
+ function buildIosSimulator() {
807
+ const triplet = 'arm64-ios-simulator'
808
+ const buildDir = join(cesiumSrc, 'build-ios-simulator')
809
+ cmakeConfigure(buildDir, [
810
+ `-DCMAKE_INSTALL_PREFIX=${stagingSim}`,
811
+ `-DVCPKG_TARGET_TRIPLET=${triplet}`,
812
+ '-DCMAKE_SYSTEM_NAME=iOS',
813
+ '-DCMAKE_OSX_SYSROOT=iphonesimulator',
814
+ '-DCMAKE_OSX_ARCHITECTURES=arm64',
815
+ '-DCMAKE_OSX_DEPLOYMENT_TARGET=15.1',
816
+ // Same warning behavior as device build to keep simulator configuration consistent.
817
+ '-DCMAKE_CXX_FLAGS=-Wno-error=overriding-option',
818
+ ])
819
+ cmakeBuildInstall(buildDir, stagingSim)
820
+ mergeVcpkgInstalled(buildDir, triplet, stagingSim)
821
+ assertFile(join(stagingSim, 'share', 'cesium-native', 'cmake', 'cesium-nativeConfig.cmake'))
822
+ const merged = join(stagingSim, 'libCesiumNativePrebuilt.a')
823
+ mergeStaticLibs(join(stagingSim, 'lib'), merged)
824
+ console.log(`iOS simulator staging + merged static lib: ${merged}`)
825
+ }
826
+
827
+ function createXcframework() {
828
+ rmSync(vendorIos, { recursive: true, force: true })
829
+ mkdirSync(vendorIos, { recursive: true })
830
+ const out = join(vendorIos, 'CesiumNative.xcframework')
831
+ rmSync(out, { recursive: true, force: true })
832
+ const devLib = join(stagingDevice, 'libCesiumNativePrebuilt.a')
833
+ const simLib = join(stagingSim, 'libCesiumNativePrebuilt.a')
834
+ const headers = join(stagingDevice, 'include')
835
+ assertFile(devLib)
836
+ assertFile(simLib)
837
+ if (!existsSync(headers)) {
838
+ throw new Error(`Expected headers at ${headers}`)
839
+ }
840
+ run('xcodebuild', [
841
+ '-create-xcframework',
842
+ '-library',
843
+ devLib,
844
+ '-headers',
845
+ headers,
846
+ '-library',
847
+ simLib,
848
+ '-headers',
849
+ headers,
850
+ '-output',
851
+ out,
852
+ ])
853
+ assertFile(join(out, 'Info.plist'))
854
+ const readme = join(vendorIos, 'README.txt')
855
+ writeFileSync(
856
+ readme,
857
+ 'Cesium Native iOS prebuilts: CesiumNative.xcframework (device + simulator).\n' +
858
+ 'Produced by `yarn run build` from vendor/cesium-native.\n'
859
+ )
860
+ writeFileSync(join(vendorIos, 'README.md'), VENDOR_IOS_README)
861
+ console.log(`XCFramework written to ${out}`)
862
+ }
863
+
864
+ function main() {
865
+ if (!existsSync(cesiumSrc)) {
866
+ console.error('vendor/cesium-native not found. Run: yarn run update')
867
+ process.exit(1)
868
+ }
869
+ ensureDarwinBuildPath()
870
+ if (!which('cmake') && !resolveExecutablePath('cmake')) {
871
+ console.error(
872
+ 'cmake must be on PATH (CMake 3.15+). Install: https://cmake.org/download/ or brew install cmake'
873
+ )
874
+ process.exit(1)
875
+ }
876
+ resolveCmakeGenerator()
877
+ ensureNinjaMakeProgram()
878
+ ensureDarwinClangEnv()
879
+ ensureDarwinSdkRoot()
880
+ resolveVcpkgRoot()
881
+
882
+ const only = process.env.CESIUM_BUILD_ONLY
883
+ if (!only || only === 'android') {
884
+ buildAndroid()
885
+ }
886
+ if (!only || only === 'ios') {
887
+ if (process.platform !== 'darwin') {
888
+ console.warn('Skipping iOS build (macOS required).')
889
+ } else {
890
+ if (!which('xcodebuild')) {
891
+ console.error('xcodebuild not found.')
892
+ process.exit(1)
893
+ }
894
+ buildIosDevice()
895
+ buildIosSimulator()
896
+ createXcframework()
897
+ }
898
+ }
899
+ }
900
+
901
+ main()