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.
- package/LICENSE +21 -0
- package/NOTICE +12 -0
- package/README.md +308 -0
- package/ReactNativeCesium.podspec +54 -0
- package/android/CMakeLists.txt +146 -0
- package/android/build.gradle +178 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/assets/cacert.pem +3529 -0
- package/android/src/main/cpp/CesiumBridgeAndroid.cpp +487 -0
- package/android/src/main/cpp/CesiumBridgeAndroid.h +94 -0
- package/android/src/main/cpp/cpp-adapter.cpp +17 -0
- package/android/src/main/cpp/vulkan/VulkanBackend.cpp +1781 -0
- package/android/src/main/cpp/vulkan/VulkanBackend.h +190 -0
- package/android/src/main/cpp/vulkan/shaders/sky.frag +86 -0
- package/android/src/main/cpp/vulkan/shaders/sky.vert +9 -0
- package/android/src/main/cpp/vulkan/shaders/terrain.frag +144 -0
- package/android/src/main/cpp/vulkan/shaders/terrain.vert +25 -0
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +84 -0
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +225 -0
- package/android/src/main/java/com/reactnativecesium/ReactNativeCesiumPackage.kt +28 -0
- package/cpp/engine/CesiumEngine.cpp +413 -0
- package/cpp/engine/CesiumEngine.hpp +90 -0
- package/cpp/engine/DeletionQueue.cpp +28 -0
- package/cpp/engine/DeletionQueue.hpp +28 -0
- package/cpp/engine/GlobeCamera.cpp +181 -0
- package/cpp/engine/GlobeCamera.hpp +64 -0
- package/cpp/engine/GltfToMesh.cpp +154 -0
- package/cpp/engine/GltfToMesh.hpp +20 -0
- package/cpp/engine/ResourcePreparer.cpp +224 -0
- package/cpp/engine/ResourcePreparer.hpp +96 -0
- package/cpp/engine/TaskProcessor.cpp +61 -0
- package/cpp/engine/TaskProcessor.hpp +43 -0
- package/cpp/engine/TileLifecycleManager.cpp +30 -0
- package/cpp/engine/TileLifecycleManager.hpp +25 -0
- package/cpp/fmt/format.h +9 -0
- package/cpp/renderer/IGPUBackend.hpp +22 -0
- package/cpp/renderer/RenderTypes.hpp +112 -0
- package/cpp/renderer/ShaderTypes.hpp +29 -0
- package/example/README.md +43 -0
- package/example/react-native-cesium-example.jpg +0 -0
- package/ios/CesiumBridge.h +55 -0
- package/ios/CesiumBridge.mm +393 -0
- package/ios/HybridCesiumView.swift +299 -0
- package/ios/ReactNativeCesium-umbrella.h +16 -0
- package/ios/metal/MetalBackend.h +82 -0
- package/ios/metal/MetalBackend.mm +839 -0
- package/ios/react_native_cesium_ensure_native.rb +12 -0
- package/ios/react_native_cesium_post_install.rb +30 -0
- package/lib/commonjs/CesiumView.js +13 -0
- package/lib/commonjs/CesiumView.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/specs/cesium-view.nitro.js +6 -0
- package/lib/commonjs/specs/cesium-view.nitro.js.map +1 -0
- package/lib/module/CesiumView.js +9 -0
- package/lib/module/CesiumView.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/specs/cesium-view.nitro.js +4 -0
- package/lib/module/specs/cesium-view.nitro.js.map +1 -0
- package/lib/typescript/src/CesiumView.d.ts +5 -0
- package/lib/typescript/src/CesiumView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts +43 -0
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -0
- package/nitro.json +30 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/ReactNativeCesium+autolinking.cmake +83 -0
- package/nitrogen/generated/android/ReactNativeCesium+autolinking.gradle +27 -0
- package/nitrogen/generated/android/ReactNativeCesiumOnLoad.cpp +58 -0
- package/nitrogen/generated/android/ReactNativeCesiumOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JCameraState.hpp +81 -0
- package/nitrogen/generated/android/c++/JCesiumMetrics.hpp +81 -0
- package/nitrogen/generated/android/c++/JFunc_void_CesiumMetrics.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.cpp +178 -0
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.hpp +83 -0
- package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.cpp +92 -0
- package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CameraState.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/CesiumMetrics.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/Func_void_CesiumMetrics.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/HybridCesiumViewSpec.kt +126 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/ReactNativeCesiumOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/views/HybridCesiumViewStateUpdater.kt +23 -0
- package/nitrogen/generated/ios/ReactNativeCesium+autolinking.rb +60 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.cpp +57 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.hpp +164 -0
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Umbrella.hpp +53 -0
- package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.mm +33 -0
- package/nitrogen/generated/ios/ReactNativeCesiumAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.hpp +157 -0
- package/nitrogen/generated/ios/c++/views/HybridCesiumViewComponent.mm +167 -0
- package/nitrogen/generated/ios/swift/CameraState.swift +59 -0
- package/nitrogen/generated/ios/swift/CesiumMetrics.swift +59 -0
- package/nitrogen/generated/ios/swift/Func_void_CameraState.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_CesiumMetrics.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec.swift +65 -0
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec_cxx.swift +306 -0
- package/nitrogen/generated/shared/c++/CameraState.hpp +107 -0
- package/nitrogen/generated/shared/c++/CesiumMetrics.hpp +107 -0
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.cpp +42 -0
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.hpp +90 -0
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.cpp +182 -0
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.hpp +122 -0
- package/nitrogen/generated/shared/json/CesiumViewConfig.json +19 -0
- package/package.json +140 -0
- package/react-native.config.js +16 -0
- package/scripts/cesium/build.mjs +901 -0
- package/scripts/cesium/clean.mjs +35 -0
- package/scripts/cesium/clone.mjs +32 -0
- package/scripts/cesium/ensure-native.mjs +116 -0
- package/scripts/cesium/vcpkg-ports/zstd/fix-emscripten-and-clang-cl.patch +31 -0
- package/scripts/cesium/vcpkg-ports/zstd/fix-windows-rc-compile.patch +13 -0
- package/scripts/cesium/vcpkg-ports/zstd/no-static-suffix.patch +13 -0
- package/scripts/cesium/vcpkg-ports/zstd/portfile.cmake +77 -0
- package/scripts/cesium/vcpkg-ports/zstd/usage +4 -0
- package/scripts/cesium/vcpkg-ports/zstd/vcpkg.json +23 -0
- package/scripts/cesium/vcpkg-triplets/arm64-ios-simulator.cmake +10 -0
- package/scripts/cesium/vcpkg-triplets/arm64-ios.cmake +14 -0
- package/src/CesiumView.tsx +13 -0
- package/src/index.ts +7 -0
- 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()
|