peachsim 0.1.1635 → 0.1.1640
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/README.md +5 -1
- package/cli/app-config.ts +14 -5
- package/cli/app-stubs.ts +62 -13
- package/cli/bridge-flow-runner.ts +2 -2
- package/cli/cloud-client.ts +60 -40
- package/cli/commands/doctor.ts +13 -5
- package/cli/commands/flow.ts +1 -1
- package/cli/commands/inspect/shared.ts +9 -4
- package/cli/commands/inspect.ts +65 -47
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/record.ts +97 -47
- package/cli/commands/swift.ts +9 -3
- package/cli/commands/upload.ts +48 -42
- package/cli/drivers/playwright-sim-host.ts +65 -42
- package/cli/main.ts +1 -1
- package/cli/outbound-endpoints.ts +7 -5
- package/cli/pause-aware-timeout.ts +4 -0
- package/cli/ws-bridge.ts +19 -10
- package/detox/attempt-events.cjs +62 -5
- package/detox/attempt-events.d.cts +7 -0
- package/detox/expectations.ts +7 -3
- package/detox/index.ts +121 -47
- package/detox/motion-change.cjs +170 -21
- package/detox/motion-change.d.cts +32 -0
- package/detox/navigation-lifecycle.ts +35 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +8 -7
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/bundle-channel.cjs +4038 -1983
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +1 -1
- package/dist-lib/detox/index.cjs +509 -86
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +3551 -1574
- package/dist-lib/expo-swift-metadata.cjs +9 -7
- package/dist-lib/expo-swift-metadata.mjs +9 -7
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +43633 -2635
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2748 -128
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +2547 -83
- package/dist-lib/native-app-identity-project.cjs +237 -50
- package/dist-lib/native-app-identity-project.mjs +237 -50
- package/dist-lib/native-app-identity.cjs +29 -30
- package/dist-lib/native-app-identity.mjs +29 -30
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +2 -2
- package/dist-lib/react-native-host-modules.mjs +2 -2
- package/dist-lib/scripts/dev-server-scanner.cjs +8 -6
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +65403 -22739
- package/dist-lib/swift-compile.cjs +93 -32
- package/dist-lib/swift-compile.mjs +93 -32
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +7 -5
- package/dist-lib/swift-submit.mjs +7 -5
- package/dist-lib/swift-toolchain.cjs +316 -41
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +7335 -5432
- package/dist-lib/vite.cjs +2857 -12
- package/dist-lib/worklet-executable.cjs +14 -2
- package/dist-lib/worklet-executable.mjs +14 -2
- package/package.json +1 -1
- package/src/backend-origin.ts +13 -6
- package/src/expo-swift-host.ts +5 -2
- package/src/expoKotlinContract.ts +4 -7
- package/src/expoSwiftContract.ts +4 -6
- package/src/host/staged-host-files.ts +9 -0
- package/src/native-app-identity-project.ts +1 -4
- package/src/native-app-identity.ts +1 -4
- package/src/nativeAppIconContract.ts +1 -4
- package/src/output-lock-stdio.ts +36 -0
- package/src/react-native-bridge-modules.ts +21 -6
- package/src/react-native-host-modules.ts +4 -1
- package/src/settings-bundle.ts +1 -4
- package/src/swift-compile.ts +91 -33
- package/src/swift-distribution.lock.json +22 -12
- package/src/swift-distribution.ts +103 -4
- package/src/swift-host.ts +89 -26
- package/src/swift-icu.ts +16 -10
- package/src/swift-objc-compile.ts +355 -0
- package/src/swift-objc-sdk.ts +689 -18
- package/src/swift-objc-standin.ts +126 -14
- package/src/swift-package-manifest.ts +39 -1
- package/src/swift-packages.ts +35 -21
- package/src/swift-standin-emit.ts +40 -7
- package/src/swift-standins.ts +404 -138
- package/src/swift-submit.ts +3 -5
- package/src/swift-toolchain.ts +378 -46
- package/src/worker-system-chunks.ts +11 -12
- package/src/worklet-executable.ts +19 -1
- package/src/xcode-project.ts +270 -30
package/src/swift-standins.ts
CHANGED
|
@@ -15,16 +15,27 @@ import fs from 'node:fs'
|
|
|
15
15
|
import path from 'node:path'
|
|
16
16
|
import { getCliVersion } from './cli-version'
|
|
17
17
|
import { cacheDir as peachCacheDir, swiftPackageCacheOptions } from './home-paths'
|
|
18
|
+
import { isRecord } from './is-record'
|
|
19
|
+
import { outputLockStdio } from './output-lock-stdio'
|
|
18
20
|
import { parsePlistSource } from './plist'
|
|
19
21
|
import {
|
|
20
22
|
swiftDistributionAt,
|
|
23
|
+
swiftImportNames,
|
|
21
24
|
swiftMacroPlugins,
|
|
22
25
|
swiftModuleDigest,
|
|
23
26
|
swiftModuleSdk,
|
|
24
27
|
swiftPeachModules,
|
|
25
28
|
swiftSdkPaths,
|
|
26
29
|
} from './swift-compile'
|
|
27
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
IOS_SDK_ID,
|
|
32
|
+
NATIVE_GRAPH_ID,
|
|
33
|
+
OBJC_IMPORT_VERSION,
|
|
34
|
+
nativeInterfaceView,
|
|
35
|
+
objcView,
|
|
36
|
+
type ObjcSurface,
|
|
37
|
+
} from './swift-objc-standin'
|
|
38
|
+
import { swiftTargetModuleName } from './swift-package'
|
|
28
39
|
import {
|
|
29
40
|
STANDIN_EMIT_VERSION,
|
|
30
41
|
STANDIN_IMPORTS,
|
|
@@ -33,10 +44,11 @@ import {
|
|
|
33
44
|
type SwiftStandinBehaviors,
|
|
34
45
|
type StandinBehavior,
|
|
35
46
|
} from './swift-standin-emit'
|
|
36
|
-
import { swiftSdkOptions } from './swift-toolchain'
|
|
47
|
+
import { swiftEnvironment, swiftSdkOptions } from './swift-toolchain'
|
|
37
48
|
import type { SwiftPackageBinary } from './swift-packages'
|
|
38
49
|
|
|
39
50
|
const TRIPLE = 'wasm32-unknown-wasip1'
|
|
51
|
+
const WASI_EMULATION = ['_WASI_EMULATED_SIGNAL', '_WASI_EMULATED_MMAN']
|
|
40
52
|
// every stand-in artifact and temporary workspace belongs to peach.
|
|
41
53
|
const cacheDir = path.join(peachCacheDir(), 'swift-standins')
|
|
42
54
|
// each binary stand-in is a target under its module's directory here.
|
|
@@ -68,10 +80,16 @@ interface Toolchain {
|
|
|
68
80
|
standinModules?: string
|
|
69
81
|
}
|
|
70
82
|
|
|
83
|
+
interface NativeFrameworkInputs {
|
|
84
|
+
dirs: string[]
|
|
85
|
+
digest: string
|
|
86
|
+
}
|
|
87
|
+
|
|
71
88
|
function exec(file: string, args: string[], cwd?: string): string {
|
|
72
89
|
return execFileSync(file, args, {
|
|
73
90
|
cwd,
|
|
74
91
|
encoding: 'utf8',
|
|
92
|
+
env: swiftEnvironment(),
|
|
75
93
|
maxBuffer: 256 * 1024 * 1024,
|
|
76
94
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
77
95
|
})
|
|
@@ -99,14 +117,20 @@ const digests = new Map<string, { stamp: string; digest: string }>()
|
|
|
99
117
|
|
|
100
118
|
function treeDigest(root: string): string {
|
|
101
119
|
const names: string[] = []
|
|
120
|
+
const ancestors = new Set<string>()
|
|
102
121
|
const walk = (dir: string) => {
|
|
122
|
+
const resolved = fs.realpathSync(dir)
|
|
123
|
+
if (ancestors.has(resolved)) throw new Error(`cyclic header directory: ${dir}`)
|
|
124
|
+
ancestors.add(resolved)
|
|
103
125
|
for (const entry of fs
|
|
104
126
|
.readdirSync(dir, { withFileTypes: true })
|
|
105
127
|
.sort((left, right) => (left.name < right.name ? -1 : 1))) {
|
|
106
128
|
const full = path.join(dir, entry.name)
|
|
107
|
-
|
|
108
|
-
|
|
129
|
+
const stat = entry.isSymbolicLink() ? fs.statSync(full) : entry
|
|
130
|
+
if (stat.isDirectory()) walk(full)
|
|
131
|
+
else if (stat.isFile()) names.push(path.relative(root, full))
|
|
109
132
|
}
|
|
133
|
+
ancestors.delete(resolved)
|
|
110
134
|
}
|
|
111
135
|
walk(root)
|
|
112
136
|
const stamp = names
|
|
@@ -222,6 +246,7 @@ const files = (dir: string, test: (name: string) => boolean): string[] =>
|
|
|
222
246
|
/** the module surfaces an iOS simulator slice describes. */
|
|
223
247
|
type Surface =
|
|
224
248
|
| { kind: 'swift'; module: string; interface: string }
|
|
249
|
+
| (ObjcSurface & { kind: 'mixed'; interface: string })
|
|
225
250
|
| { kind: 'c'; module: string; modulemap: string; headers: string }
|
|
226
251
|
| (ObjcSurface & { kind: 'objc' })
|
|
227
252
|
|
|
@@ -262,15 +287,27 @@ function surfaces(xcframeworkDir: string): Surface[] {
|
|
|
262
287
|
)
|
|
263
288
|
const chosen =
|
|
264
289
|
interfaces.find((name) => name.startsWith('arm64-')) ?? interfaces[0] ?? null
|
|
290
|
+
const modulemap = path.join(framework, 'Modules', 'module.modulemap')
|
|
265
291
|
if (chosen) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
292
|
+
const file = path.join(swiftmodule, chosen)
|
|
293
|
+
const underlying = [
|
|
294
|
+
...fs
|
|
295
|
+
.readFileSync(file, 'utf8')
|
|
296
|
+
.matchAll(/^(?:@_exported[ \t]+)?import[ \t]+(\w+)[ \t]*$/gm),
|
|
297
|
+
].some((match) => match[1] === module)
|
|
298
|
+
if (underlying) {
|
|
299
|
+
if (!fs.existsSync(modulemap))
|
|
300
|
+
throw new Error(`${module} imports its underlying module without a modulemap`)
|
|
301
|
+
found.push({
|
|
302
|
+
kind: 'mixed',
|
|
303
|
+
module,
|
|
304
|
+
interface: file,
|
|
305
|
+
modulemap,
|
|
306
|
+
headers: path.join(framework, 'Headers'),
|
|
307
|
+
})
|
|
308
|
+
} else found.push({ kind: 'swift', module, interface: file })
|
|
271
309
|
continue
|
|
272
310
|
}
|
|
273
|
-
const modulemap = path.join(framework, 'Modules', 'module.modulemap')
|
|
274
311
|
if (fs.existsSync(modulemap))
|
|
275
312
|
found.push(headerSurface(module, modulemap, path.join(framework, 'Headers')))
|
|
276
313
|
}
|
|
@@ -286,6 +323,14 @@ function surfaces(xcframeworkDir: string): Surface[] {
|
|
|
286
323
|
return found
|
|
287
324
|
}
|
|
288
325
|
|
|
326
|
+
export function standinsNeedNativeSdk(binaries: readonly SwiftPackageBinary[]): boolean {
|
|
327
|
+
return binaries.some(
|
|
328
|
+
(binary) =>
|
|
329
|
+
binary.publicHeaders === undefined &&
|
|
330
|
+
surfaces(xcframework(binary).dir).some((surface) => surface.kind === 'mixed'),
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
|
|
289
334
|
// the peach modules an interface imports, compiled for wasm: a distribution
|
|
290
335
|
// ships them; a checkout builds the ones named into its own build directory,
|
|
291
336
|
// with the flags scripts/build.sh uses, so the two share one build.
|
|
@@ -366,11 +411,14 @@ export function swiftInterfaceForWasm(text: string): string {
|
|
|
366
411
|
? rooted.replace(/^(?=import[ \t])/m, 'import Foundation\n')
|
|
367
412
|
: rooted
|
|
368
413
|
return foundation
|
|
369
|
-
.replace(
|
|
370
|
-
flags
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
414
|
+
.replace(
|
|
415
|
+
/^(\/\/ swift-module-flags:.*)$/m,
|
|
416
|
+
(flags) =>
|
|
417
|
+
flags
|
|
418
|
+
.replace(/-target \S+/, `-target ${TRIPLE}`)
|
|
419
|
+
.replace(/\s-enable-objc-interop\b/, '')
|
|
420
|
+
.replace(/\s-target-variant \S+/, '') +
|
|
421
|
+
` ${WASI_EMULATION.map((name) => `-Xcc -D${name}`).join(' ')}`,
|
|
374
422
|
)
|
|
375
423
|
.replace(
|
|
376
424
|
/@(?:objc(?:\s*\([^()]*\))?|objcMembers|nonobjc|IBOutlet|IBAction|IBInspectable|IBDesignable|_objcRuntimeName\([^()]*\))(?![\w(])/g,
|
|
@@ -384,17 +432,14 @@ function swiftStandin(
|
|
|
384
432
|
toolchain: Toolchain,
|
|
385
433
|
work: string,
|
|
386
434
|
behavior: ReadonlyMap<string, StandinBehavior>,
|
|
435
|
+
siblings: ReadonlySet<string>,
|
|
387
436
|
): SwiftStandin {
|
|
388
437
|
const text = swiftInterfaceForWasm(fs.readFileSync(surface.interface, 'utf8'))
|
|
389
438
|
const search = path.join(work, 'interfaces')
|
|
390
439
|
const moduleDir = path.join(search, `${surface.module}.swiftmodule`)
|
|
391
440
|
fs.mkdirSync(moduleDir, { recursive: true })
|
|
392
441
|
fs.writeFileSync(path.join(moduleDir, `${TRIPLE}.swiftinterface`), text)
|
|
393
|
-
const imports =
|
|
394
|
-
...text.matchAll(
|
|
395
|
-
/^(?:@_exported[ \t]+)?import[ \t]+(?:(?:struct|class|enum|protocol|typealias|func|var|let)[ \t]+)?(\w+)/gm,
|
|
396
|
-
),
|
|
397
|
-
].map((match) => match[1]!)
|
|
442
|
+
const imports = swiftImportNames(text)
|
|
398
443
|
const wasm = wasmFlags(toolchain, imports)
|
|
399
444
|
const out = path.join(work, 'graphs')
|
|
400
445
|
fs.mkdirSync(out, { recursive: true })
|
|
@@ -425,6 +470,37 @@ function swiftStandin(
|
|
|
425
470
|
toolchain,
|
|
426
471
|
work,
|
|
427
472
|
behavior,
|
|
473
|
+
[...new Set(imports)].filter((module) => siblings.has(module)),
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function mixedStandin(
|
|
478
|
+
surface: Extract<Surface, { kind: 'mixed' }>,
|
|
479
|
+
binary: SwiftPackageBinary,
|
|
480
|
+
toolchain: Toolchain,
|
|
481
|
+
work: string,
|
|
482
|
+
behavior: ReadonlyMap<string, StandinBehavior>,
|
|
483
|
+
frameworkDirs: readonly string[],
|
|
484
|
+
siblings: ReadonlySet<string>,
|
|
485
|
+
): SwiftStandin {
|
|
486
|
+
const view = nativeInterfaceView(surface, frameworkDirs, work)
|
|
487
|
+
const provided = new Set(swiftPeachModules(toolchain.moduleRoot))
|
|
488
|
+
const imports = [
|
|
489
|
+
...new Set(swiftImportNames(fs.readFileSync(surface.interface, 'utf8'))),
|
|
490
|
+
].filter(
|
|
491
|
+
(module) =>
|
|
492
|
+
module !== surface.module && (provided.has(module) || siblings.has(module)),
|
|
493
|
+
)
|
|
494
|
+
return graphStandin(
|
|
495
|
+
surface.module,
|
|
496
|
+
view.graphs,
|
|
497
|
+
view.values,
|
|
498
|
+
wasmFlags(toolchain, imports),
|
|
499
|
+
binary,
|
|
500
|
+
toolchain,
|
|
501
|
+
work,
|
|
502
|
+
behavior,
|
|
503
|
+
imports,
|
|
428
504
|
)
|
|
429
505
|
}
|
|
430
506
|
|
|
@@ -442,10 +518,7 @@ function wasmFlags(toolchain: Toolchain, imports: string[]): string[] {
|
|
|
442
518
|
'-resource-dir',
|
|
443
519
|
resources,
|
|
444
520
|
// the sdk toolset's emulation defines, which raw swiftc does not read
|
|
445
|
-
'-Xcc',
|
|
446
|
-
'-D_WASI_EMULATED_SIGNAL',
|
|
447
|
-
'-Xcc',
|
|
448
|
-
'-D_WASI_EMULATED_MMAN',
|
|
521
|
+
...WASI_EMULATION.flatMap((name) => ['-Xcc', `-D${name}`]),
|
|
449
522
|
...peachModuleDirs(toolchain, imports).flatMap((dir) => ['-I', dir]),
|
|
450
523
|
...(toolchain.standinModules ? ['-I', toolchain.standinModules] : []),
|
|
451
524
|
]
|
|
@@ -475,7 +548,9 @@ function objcStandin(
|
|
|
475
548
|
toolchain,
|
|
476
549
|
work,
|
|
477
550
|
behavior,
|
|
478
|
-
binary.headerDependencies?.map((dependency) =>
|
|
551
|
+
binary.headerDependencies?.map((dependency) =>
|
|
552
|
+
swiftTargetModuleName(dependency.module),
|
|
553
|
+
),
|
|
479
554
|
)
|
|
480
555
|
}
|
|
481
556
|
|
|
@@ -528,17 +603,21 @@ function graphStandin(
|
|
|
528
603
|
fs.writeFileSync(file, source)
|
|
529
604
|
const check = spawnSync(
|
|
530
605
|
path.join(toolchain.toolchainBin, 'swiftc'),
|
|
606
|
+
// emitting the module runs the diagnostics a typecheck skips, such as
|
|
607
|
+
// literal overflow, which the app's build of the stand-in reaches
|
|
531
608
|
[
|
|
532
|
-
'-
|
|
609
|
+
'-emit-module',
|
|
533
610
|
'-parse-as-library',
|
|
534
611
|
'-swift-version',
|
|
535
612
|
'5',
|
|
536
613
|
'-module-name',
|
|
537
614
|
module,
|
|
538
615
|
...wasm,
|
|
616
|
+
'-emit-module-path',
|
|
617
|
+
path.join(work, `${module}.swiftmodule`),
|
|
539
618
|
file,
|
|
540
619
|
],
|
|
541
|
-
{ encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 },
|
|
620
|
+
{ encoding: 'utf8', env: swiftEnvironment(), maxBuffer: 256 * 1024 * 1024 },
|
|
542
621
|
)
|
|
543
622
|
if (check.status === 0)
|
|
544
623
|
return {
|
|
@@ -993,51 +1072,91 @@ export function standinLibrary(
|
|
|
993
1072
|
throw new Error(`cargo built ${crate} for ${RUST_TARGET} but reported no ${library}`)
|
|
994
1073
|
}
|
|
995
1074
|
|
|
996
|
-
// source preflight
|
|
997
|
-
//
|
|
998
|
-
function
|
|
999
|
-
|
|
1075
|
+
// source preflight admits the complete closure once, including ignored local
|
|
1076
|
+
// frameworks. target generation and prerequisite modules stay in that one job.
|
|
1077
|
+
function sourceStandins(
|
|
1078
|
+
binaries: readonly SwiftPackageBinary[],
|
|
1000
1079
|
toolchain: Toolchain,
|
|
1001
1080
|
provided: ReadonlySet<string>,
|
|
1002
1081
|
behavior: SwiftStandinBehaviors,
|
|
1003
|
-
):
|
|
1082
|
+
): SwiftStandins {
|
|
1004
1083
|
const repo = path.resolve(toolchain.moduleRoot, '../..')
|
|
1005
1084
|
fs.mkdirSync(cacheDir, { recursive: true })
|
|
1085
|
+
const generation = standinGenerationInputs(binaries, toolchain, behavior)
|
|
1086
|
+
const cached = path.join(
|
|
1087
|
+
cacheDir,
|
|
1088
|
+
'closures',
|
|
1089
|
+
`${key(generation, JSON.stringify([...provided].sort()))}.json`,
|
|
1090
|
+
)
|
|
1091
|
+
const targets = new Set(binaries.map((binary) => binary.target))
|
|
1092
|
+
if (fs.existsSync(cached))
|
|
1093
|
+
return readStandinResults(
|
|
1094
|
+
JSON.parse(fs.readFileSync(cached, 'utf8')),
|
|
1095
|
+
generation,
|
|
1096
|
+
targets,
|
|
1097
|
+
)
|
|
1006
1098
|
const work = fs.mkdtempSync(path.join(cacheDir, 'request-'))
|
|
1007
1099
|
try {
|
|
1008
|
-
const artifact =
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1100
|
+
const artifact = path.join(work, 'artifacts')
|
|
1101
|
+
fs.mkdirSync(artifact)
|
|
1102
|
+
const local: SwiftPackageBinary[] = []
|
|
1103
|
+
const gaps = new Map<string, string>()
|
|
1104
|
+
const headers = new Map<string, string>()
|
|
1105
|
+
for (const [index, binary] of binaries.entries()) {
|
|
1106
|
+
try {
|
|
1107
|
+
if (binary.publicHeaders !== undefined) {
|
|
1108
|
+
const copyHeader = (relative: string) => {
|
|
1109
|
+
const source = fs.realpathSync(path.join(binary.dir, relative))
|
|
1110
|
+
let destination = headers.get(source)
|
|
1111
|
+
if (destination === undefined) {
|
|
1112
|
+
destination = `headers/${headers.size}`
|
|
1113
|
+
fs.cpSync(source, path.join(artifact, destination), {
|
|
1114
|
+
recursive: true,
|
|
1115
|
+
dereference: true,
|
|
1116
|
+
})
|
|
1117
|
+
headers.set(source, destination)
|
|
1118
|
+
}
|
|
1119
|
+
return destination
|
|
1120
|
+
}
|
|
1121
|
+
local.push({
|
|
1122
|
+
...binary,
|
|
1123
|
+
dir: artifact,
|
|
1124
|
+
url: null,
|
|
1125
|
+
checksum: null,
|
|
1126
|
+
publicHeaders: copyHeader(binary.publicHeaders),
|
|
1127
|
+
headerDependencies: (binary.headerDependencies ?? []).map((dependency) => ({
|
|
1128
|
+
module: dependency.module,
|
|
1129
|
+
path: copyHeader(dependency.path),
|
|
1130
|
+
})),
|
|
1131
|
+
})
|
|
1132
|
+
} else {
|
|
1133
|
+
const resolved = xcframework(binary)
|
|
1134
|
+
const dir = path.join(artifact, String(index), path.basename(resolved.dir))
|
|
1135
|
+
fs.cpSync(resolved.dir, dir, { recursive: true, dereference: true })
|
|
1136
|
+
local.push({ ...binary, dir, url: null, checksum: null })
|
|
1137
|
+
}
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
gaps.set(binary.target, error instanceof Error ? error.message : String(error))
|
|
1140
|
+
}
|
|
1029
1141
|
}
|
|
1030
|
-
|
|
1142
|
+
if (local.length === 0) return { standins: [], gaps }
|
|
1143
|
+
const preparedGeneration = standinGenerationInputs(local, toolchain, behavior)
|
|
1144
|
+
if (generation !== standinGenerationInputs(binaries, toolchain, behavior))
|
|
1145
|
+
throw new Error('Swift stand-in inputs changed during preparation')
|
|
1031
1146
|
const request = path.join(work, 'request.json')
|
|
1032
1147
|
const delivery = path.join(work, 'delivery')
|
|
1033
1148
|
fs.writeFileSync(
|
|
1034
1149
|
request,
|
|
1035
1150
|
JSON.stringify({
|
|
1036
|
-
|
|
1151
|
+
binaries: local.map((binary) => ({
|
|
1152
|
+
...binary,
|
|
1153
|
+
dir: path.relative(artifact, binary.dir) || '.',
|
|
1154
|
+
})),
|
|
1037
1155
|
provided: [...provided],
|
|
1038
1156
|
behavior,
|
|
1039
|
-
generation,
|
|
1157
|
+
generation: preparedGeneration,
|
|
1040
1158
|
release: toolchain.release,
|
|
1159
|
+
native: standinsNeedNativeSdk(local),
|
|
1041
1160
|
}),
|
|
1042
1161
|
)
|
|
1043
1162
|
const build = spawnSync(
|
|
@@ -1047,56 +1166,104 @@ function sourceBinaryStandins(
|
|
|
1047
1166
|
'--request',
|
|
1048
1167
|
request,
|
|
1049
1168
|
'--artifact',
|
|
1050
|
-
artifact
|
|
1169
|
+
artifact,
|
|
1051
1170
|
'--delivery-dir',
|
|
1052
1171
|
delivery,
|
|
1053
1172
|
],
|
|
1054
|
-
{
|
|
1173
|
+
{
|
|
1174
|
+
cwd: repo,
|
|
1175
|
+
encoding: 'utf8',
|
|
1176
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
1177
|
+
stdio: outputLockStdio(['ignore', 'pipe', 'pipe']),
|
|
1178
|
+
},
|
|
1055
1179
|
)
|
|
1056
1180
|
if (build.stdout) process.stdout.write(build.stdout)
|
|
1057
1181
|
if (build.stderr) process.stderr.write(build.stderr)
|
|
1058
1182
|
if (build.error || build.status !== 0)
|
|
1059
1183
|
throw new Error(
|
|
1060
|
-
`source stand-in build for ${binary.target} failed (${build.error?.message ?? build.signal ?? `exit ${build.status}`}): ${build.stderr?.trim().slice(-4000) || build.stdout?.trim().slice(-4000) || 'builder returned no diagnostic'}`,
|
|
1184
|
+
`source stand-in build for ${local.map((binary) => binary.target).join(', ')} failed (${build.error?.message ?? build.signal ?? `exit ${build.status}`}): ${build.stderr?.trim().slice(-4000) || build.stdout?.trim().slice(-4000) || 'builder returned no diagnostic'}`,
|
|
1061
1185
|
)
|
|
1062
1186
|
const output = path.join(delivery, 'standins.json')
|
|
1063
1187
|
if (!fs.existsSync(output))
|
|
1064
|
-
throw new Error(
|
|
1065
|
-
`source stand-in builder returned no standins.json for ${binary.target}`,
|
|
1066
|
-
)
|
|
1188
|
+
throw new Error('source stand-in builder returned no standins.json')
|
|
1067
1189
|
const receipt: unknown = JSON.parse(fs.readFileSync(output, 'utf8'))
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
receipt.generation !== generation ||
|
|
1073
|
-
!('result' in receipt)
|
|
1074
|
-
)
|
|
1075
|
-
throw new Error('Swift stand-in builder source differs from the caller')
|
|
1076
|
-
const result = receipt.result
|
|
1077
|
-
if (typeof result === 'string') throw new Error(result)
|
|
1078
|
-
if (
|
|
1079
|
-
!Array.isArray(result) ||
|
|
1080
|
-
!result.every(
|
|
1081
|
-
(item) =>
|
|
1082
|
-
item &&
|
|
1083
|
-
typeof item === 'object' &&
|
|
1084
|
-
typeof item.module === 'string' &&
|
|
1085
|
-
typeof item.target === 'string' &&
|
|
1086
|
-
item.target === binary.target &&
|
|
1087
|
-
item.files &&
|
|
1088
|
-
typeof item.files === 'object' &&
|
|
1089
|
-
!Array.isArray(item.files) &&
|
|
1090
|
-
Object.values(item.files).every((text) => typeof text === 'string'),
|
|
1091
|
-
)
|
|
1190
|
+
const result = readStandinResults(
|
|
1191
|
+
receipt,
|
|
1192
|
+
preparedGeneration,
|
|
1193
|
+
new Set(local.map((binary) => binary.target)),
|
|
1092
1194
|
)
|
|
1093
|
-
|
|
1195
|
+
if (generation !== standinGenerationInputs(binaries, toolchain, behavior))
|
|
1196
|
+
throw new Error('Swift stand-in inputs changed during generation')
|
|
1197
|
+
for (const [target, reason] of gaps) result.gaps.set(target, reason)
|
|
1198
|
+
// failures retry against the per-target generation cache on the builder.
|
|
1199
|
+
// only a complete successful closure skips the next admission entirely.
|
|
1200
|
+
if (result.gaps.size === 0 && isRecord(receipt)) {
|
|
1201
|
+
fs.mkdirSync(path.dirname(cached), { recursive: true })
|
|
1202
|
+
const pending = `${cached}.${process.pid}.tmp`
|
|
1203
|
+
fs.writeFileSync(pending, JSON.stringify({ ...receipt, generation }))
|
|
1204
|
+
fs.renameSync(pending, cached)
|
|
1205
|
+
}
|
|
1094
1206
|
return result
|
|
1095
1207
|
} finally {
|
|
1096
1208
|
fs.rmSync(work, { recursive: true, force: true })
|
|
1097
1209
|
}
|
|
1098
1210
|
}
|
|
1099
1211
|
|
|
1212
|
+
function readStandinResults(
|
|
1213
|
+
receipt: unknown,
|
|
1214
|
+
generation: string,
|
|
1215
|
+
targets: ReadonlySet<string>,
|
|
1216
|
+
): SwiftStandins {
|
|
1217
|
+
if (!isRecord(receipt) || receipt.generation !== generation)
|
|
1218
|
+
throw new Error('Swift stand-in builder source differs from the caller')
|
|
1219
|
+
if (!Array.isArray(receipt.results) || receipt.results.length !== targets.size)
|
|
1220
|
+
throw new Error('invalid Swift stand-in builder results')
|
|
1221
|
+
const standins: SwiftStandin[] = []
|
|
1222
|
+
const gaps = new Map<string, string>()
|
|
1223
|
+
const seen = new Set<string>()
|
|
1224
|
+
for (const entry of receipt.results) {
|
|
1225
|
+
if (
|
|
1226
|
+
!isRecord(entry) ||
|
|
1227
|
+
typeof entry.target !== 'string' ||
|
|
1228
|
+
!targets.has(entry.target) ||
|
|
1229
|
+
seen.has(entry.target)
|
|
1230
|
+
)
|
|
1231
|
+
throw new Error('invalid Swift stand-in builder target')
|
|
1232
|
+
seen.add(entry.target)
|
|
1233
|
+
if (typeof entry.result === 'string') {
|
|
1234
|
+
gaps.set(entry.target, entry.result)
|
|
1235
|
+
continue
|
|
1236
|
+
}
|
|
1237
|
+
if (!Array.isArray(entry.result))
|
|
1238
|
+
throw new Error('invalid Swift stand-in builder result')
|
|
1239
|
+
for (const item of entry.result) {
|
|
1240
|
+
if (
|
|
1241
|
+
!isRecord(item) ||
|
|
1242
|
+
typeof item.module !== 'string' ||
|
|
1243
|
+
item.target !== entry.target ||
|
|
1244
|
+
!isRecord(item.files) ||
|
|
1245
|
+
!Object.values(item.files).every((text) => typeof text === 'string') ||
|
|
1246
|
+
(item.dependencies !== undefined &&
|
|
1247
|
+
(!Array.isArray(item.dependencies) ||
|
|
1248
|
+
!item.dependencies.every((name) => typeof name === 'string')))
|
|
1249
|
+
)
|
|
1250
|
+
throw new Error('invalid Swift stand-in builder result')
|
|
1251
|
+
const files: Record<string, string> = {}
|
|
1252
|
+
for (const [name, text] of Object.entries(item.files)) {
|
|
1253
|
+
if (typeof text !== 'string') throw new Error('invalid Swift stand-in file')
|
|
1254
|
+
files[name] = text
|
|
1255
|
+
}
|
|
1256
|
+
standins.push({
|
|
1257
|
+
module: item.module,
|
|
1258
|
+
target: entry.target,
|
|
1259
|
+
files,
|
|
1260
|
+
...(item.dependencies === undefined ? {} : { dependencies: item.dependencies }),
|
|
1261
|
+
})
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return { standins, gaps }
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1100
1267
|
const built = new Map<string, SwiftStandin[] | string>()
|
|
1101
1268
|
|
|
1102
1269
|
/** what stand-ins are generated from besides the surfaces' files: the
|
|
@@ -1111,13 +1278,14 @@ export function standinGenerationInputs(
|
|
|
1111
1278
|
const { moduleRoot, release } = toolchain
|
|
1112
1279
|
const sdk = swiftModuleSdk(moduleRoot)
|
|
1113
1280
|
const parts = [
|
|
1114
|
-
'standin/
|
|
1281
|
+
'standin/v9',
|
|
1115
1282
|
release,
|
|
1116
1283
|
sdk.wasmSdkId,
|
|
1117
1284
|
sdk.wasmSdkChecksum,
|
|
1118
1285
|
swiftModuleDigest(moduleRoot).toString('hex'),
|
|
1119
1286
|
`emit/${STANDIN_EMIT_VERSION}`,
|
|
1120
1287
|
`ios-sdk/${IOS_SDK_ID}`,
|
|
1288
|
+
`objc-import/${OBJC_IMPORT_VERSION}`,
|
|
1121
1289
|
// a released cli can change the emitter without anyone bumping the constant
|
|
1122
1290
|
`cli/${getCliVersion()}`,
|
|
1123
1291
|
]
|
|
@@ -1125,7 +1293,7 @@ export function standinGenerationInputs(
|
|
|
1125
1293
|
binaries.flatMap((binary) => {
|
|
1126
1294
|
try {
|
|
1127
1295
|
return binary.publicHeaders !== undefined
|
|
1128
|
-
? [binary.target]
|
|
1296
|
+
? [swiftTargetModuleName(binary.target)]
|
|
1129
1297
|
: surfaces(xcframework(binary).dir).map((surface) => surface.module)
|
|
1130
1298
|
} catch {
|
|
1131
1299
|
return []
|
|
@@ -1147,7 +1315,22 @@ export function standinGenerationInputs(
|
|
|
1147
1315
|
),
|
|
1148
1316
|
)
|
|
1149
1317
|
for (const binary of binaries) {
|
|
1318
|
+
if (
|
|
1319
|
+
binary.publicHeaders !== undefined &&
|
|
1320
|
+
swiftTargetModuleName(binary.target) !== binary.target
|
|
1321
|
+
)
|
|
1322
|
+
parts.push(`module/${swiftTargetModuleName(binary.target)}`)
|
|
1150
1323
|
try {
|
|
1324
|
+
if (
|
|
1325
|
+
binary.publicHeaders === undefined &&
|
|
1326
|
+
surfaces(xcframework(binary).dir).some((surface) => surface.kind === 'swift')
|
|
1327
|
+
)
|
|
1328
|
+
parts.push(`interface-emulation/${WASI_EMULATION.join(',')}`)
|
|
1329
|
+
if (
|
|
1330
|
+
binary.publicHeaders === undefined &&
|
|
1331
|
+
surfaces(xcframework(binary).dir).some((surface) => surface.kind === 'mixed')
|
|
1332
|
+
)
|
|
1333
|
+
parts.push(`native-graph/${NATIVE_GRAPH_ID}`)
|
|
1151
1334
|
parts.push(
|
|
1152
1335
|
binary.target,
|
|
1153
1336
|
binary.source,
|
|
@@ -1158,7 +1341,7 @@ export function standinGenerationInputs(
|
|
|
1158
1341
|
treeDigest(path.join(binary.dir, binary.publicHeaders)),
|
|
1159
1342
|
...(binary.headerDependencies ?? []).map(
|
|
1160
1343
|
(dependency) =>
|
|
1161
|
-
`${dependency.module}\0${treeDigest(path.join(binary.dir, dependency.path))}`,
|
|
1344
|
+
`${swiftTargetModuleName(dependency.module)}\0${treeDigest(path.join(binary.dir, dependency.path))}`,
|
|
1162
1345
|
),
|
|
1163
1346
|
].join('\0')
|
|
1164
1347
|
: xcframework(binary).digest,
|
|
@@ -1187,6 +1370,8 @@ function binaryStandins(
|
|
|
1187
1370
|
toolchain: Toolchain,
|
|
1188
1371
|
provided: ReadonlySet<string>,
|
|
1189
1372
|
behavior: SwiftStandinBehaviors,
|
|
1373
|
+
frameworks: NativeFrameworkInputs,
|
|
1374
|
+
siblings: ReadonlySet<string>,
|
|
1190
1375
|
): SwiftStandin[] | string {
|
|
1191
1376
|
if (provided.has(binary.target)) return []
|
|
1192
1377
|
// a local artifact a script downloads or builds is absent from a fresh
|
|
@@ -1201,6 +1386,7 @@ function binaryStandins(
|
|
|
1201
1386
|
try {
|
|
1202
1387
|
if (binary.publicHeaders !== undefined) {
|
|
1203
1388
|
const headers = path.join(binary.dir, binary.publicHeaders)
|
|
1389
|
+
const module = swiftTargetModuleName(binary.target)
|
|
1204
1390
|
const modulemap = path.join(work, 'module.modulemap')
|
|
1205
1391
|
const supplied = path.join(headers, 'module.modulemap')
|
|
1206
1392
|
const roots = files(headers, (name) => name.endsWith('.h'))
|
|
@@ -1210,16 +1396,16 @@ function binaryStandins(
|
|
|
1210
1396
|
modulemap,
|
|
1211
1397
|
fs.existsSync(supplied)
|
|
1212
1398
|
? fs.readFileSync(supplied, 'utf8')
|
|
1213
|
-
: `module ${
|
|
1399
|
+
: `module ${module} {\n${roots.map((file) => ` header "${file}"`).join('\n')}\n export *\n}\n`,
|
|
1214
1400
|
)
|
|
1215
1401
|
all = [
|
|
1216
1402
|
{
|
|
1217
1403
|
kind: 'objc',
|
|
1218
|
-
module
|
|
1404
|
+
module,
|
|
1219
1405
|
modulemap,
|
|
1220
1406
|
headers,
|
|
1221
1407
|
dependencies: binary.headerDependencies?.map((dependency) => ({
|
|
1222
|
-
module: dependency.module,
|
|
1408
|
+
module: swiftTargetModuleName(dependency.module),
|
|
1223
1409
|
headers: path.join(binary.dir, dependency.path),
|
|
1224
1410
|
})),
|
|
1225
1411
|
},
|
|
@@ -1228,7 +1414,7 @@ function binaryStandins(
|
|
|
1228
1414
|
treeDigest(headers),
|
|
1229
1415
|
...(binary.headerDependencies ?? []).map(
|
|
1230
1416
|
(dependency) =>
|
|
1231
|
-
`${dependency.module}\0${treeDigest(path.join(binary.dir, dependency.path))}`,
|
|
1417
|
+
`${swiftTargetModuleName(dependency.module)}\0${treeDigest(path.join(binary.dir, dependency.path))}`,
|
|
1232
1418
|
),
|
|
1233
1419
|
].join('\0')
|
|
1234
1420
|
} else {
|
|
@@ -1252,11 +1438,14 @@ function binaryStandins(
|
|
|
1252
1438
|
standinGenerationInputs([binary], toolchain, behavior),
|
|
1253
1439
|
)
|
|
1254
1440
|
hash.update(digest)
|
|
1441
|
+
hash.update([...siblings].sort().join('\0'))
|
|
1442
|
+
if (found.some((surface) => surface.kind === 'mixed')) hash.update(frameworks.digest)
|
|
1255
1443
|
for (const surface of found) {
|
|
1256
1444
|
hash.update(`${surface.kind}\0${surface.module}\0`)
|
|
1257
1445
|
for (const file of surface.kind === 'swift'
|
|
1258
1446
|
? [surface.interface]
|
|
1259
1447
|
: [
|
|
1448
|
+
...(surface.kind === 'mixed' ? [surface.interface] : []),
|
|
1260
1449
|
surface.modulemap,
|
|
1261
1450
|
...files(surface.headers, (name) => name.endsWith('.h')).map((file) =>
|
|
1262
1451
|
path.join(surface.headers, file),
|
|
@@ -1279,44 +1468,47 @@ function binaryStandins(
|
|
|
1279
1468
|
}
|
|
1280
1469
|
let result: SwiftStandin[] | string
|
|
1281
1470
|
try {
|
|
1282
|
-
result =
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
surface,
|
|
1308
|
-
binary,
|
|
1309
|
-
toolchain,
|
|
1310
|
-
dir,
|
|
1311
|
-
new Map(Object.entries(configured.get(surface.module) ?? {})),
|
|
1312
|
-
)
|
|
1313
|
-
: cStandin(surface, binary, toolchain, dir)
|
|
1314
|
-
} catch (error) {
|
|
1315
|
-
throw new Error(
|
|
1316
|
-
`no stand-in for ${surface.module}: ${error instanceof Error && !('stderr' in error) ? error.message : failure(error)}`,
|
|
1471
|
+
result = found.map((surface) => {
|
|
1472
|
+
const dir = path.join(work, surface.module)
|
|
1473
|
+
try {
|
|
1474
|
+
if (surface.kind === 'c' && configured.has(surface.module))
|
|
1475
|
+
throw new Error(
|
|
1476
|
+
"Configured behavior requires the framework's Swift declarations",
|
|
1477
|
+
)
|
|
1478
|
+
return surface.kind === 'mixed'
|
|
1479
|
+
? mixedStandin(
|
|
1480
|
+
surface,
|
|
1481
|
+
binary,
|
|
1482
|
+
toolchain,
|
|
1483
|
+
dir,
|
|
1484
|
+
new Map(Object.entries(configured.get(surface.module) ?? {})),
|
|
1485
|
+
frameworks.dirs,
|
|
1486
|
+
siblings,
|
|
1487
|
+
)
|
|
1488
|
+
: surface.kind === 'swift'
|
|
1489
|
+
? swiftStandin(
|
|
1490
|
+
surface,
|
|
1491
|
+
binary,
|
|
1492
|
+
toolchain,
|
|
1493
|
+
dir,
|
|
1494
|
+
new Map(Object.entries(configured.get(surface.module) ?? {})),
|
|
1495
|
+
siblings,
|
|
1317
1496
|
)
|
|
1318
|
-
|
|
1319
|
-
|
|
1497
|
+
: surface.kind === 'objc'
|
|
1498
|
+
? objcStandin(
|
|
1499
|
+
surface,
|
|
1500
|
+
binary,
|
|
1501
|
+
toolchain,
|
|
1502
|
+
dir,
|
|
1503
|
+
new Map(Object.entries(configured.get(surface.module) ?? {})),
|
|
1504
|
+
)
|
|
1505
|
+
: cStandin(surface, binary, toolchain, dir)
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
throw new Error(
|
|
1508
|
+
`no stand-in for ${surface.module}: ${error instanceof Error && !('stderr' in error) ? error.message : failure(error)}`,
|
|
1509
|
+
)
|
|
1510
|
+
}
|
|
1511
|
+
})
|
|
1320
1512
|
if (typeof result === 'string') throw new Error(result)
|
|
1321
1513
|
fs.mkdirSync(path.dirname(cached), { recursive: true })
|
|
1322
1514
|
// publish a complete entry so concurrent workspaces never read partial json.
|
|
@@ -1352,26 +1544,100 @@ export function swiftStandins(
|
|
|
1352
1544
|
provided: ReadonlySet<string> = new Set(),
|
|
1353
1545
|
behavior: SwiftStandinBehaviors = {},
|
|
1354
1546
|
): SwiftStandins {
|
|
1547
|
+
const requested = binaries.filter((binary) => !provided.has(binary.target))
|
|
1548
|
+
if (requested.length === 0) return { standins: [], gaps: new Map() }
|
|
1549
|
+
if (
|
|
1550
|
+
process.platform === 'darwin' &&
|
|
1551
|
+
process.env.TM_EXEC_BUILD_PLATFORM !== 'mac' &&
|
|
1552
|
+
process.env.TM_SESSION &&
|
|
1553
|
+
process.env.CI !== 'true' &&
|
|
1554
|
+
toolchain.moduleRoot === path.resolve(import.meta.dirname, '../../sootsim-swift') &&
|
|
1555
|
+
!swiftDistributionAt(toolchain.moduleRoot)
|
|
1556
|
+
)
|
|
1557
|
+
return sourceStandins(requested, toolchain, provided, behavior)
|
|
1355
1558
|
const standins: SwiftStandin[] = []
|
|
1356
1559
|
const gaps = new Map<string, string>()
|
|
1357
1560
|
fs.mkdirSync(cacheDir, { recursive: true })
|
|
1358
1561
|
const modules = fs.mkdtempSync(path.join(cacheDir, 'modules-'))
|
|
1562
|
+
const frameworkDirs = new Set<string>()
|
|
1563
|
+
const frameworkInputs: string[] = []
|
|
1564
|
+
const byModule = new Map(
|
|
1565
|
+
binaries.map((binary) => [swiftTargetModuleName(binary.target), binary]),
|
|
1566
|
+
)
|
|
1567
|
+
// the modules each binary's swift interfaces import
|
|
1568
|
+
const interfaceImports = new Map<SwiftPackageBinary, Set<string>>()
|
|
1569
|
+
for (const binary of binaries) {
|
|
1570
|
+
if (binary.publicHeaders !== undefined) continue
|
|
1571
|
+
try {
|
|
1572
|
+
const artifact = xcframework(binary)
|
|
1573
|
+
frameworkInputs.push(`${binary.target}\0${artifact.digest}`)
|
|
1574
|
+
const imports = new Set<string>()
|
|
1575
|
+
interfaceImports.set(binary, imports)
|
|
1576
|
+
for (const surface of surfaces(artifact.dir)) {
|
|
1577
|
+
byModule.set(surface.module, binary)
|
|
1578
|
+
if (surface.kind === 'swift' || surface.kind === 'mixed')
|
|
1579
|
+
for (const module of swiftImportNames(
|
|
1580
|
+
fs.readFileSync(surface.interface, 'utf8'),
|
|
1581
|
+
))
|
|
1582
|
+
imports.add(module)
|
|
1583
|
+
if (surface.kind === 'c') continue
|
|
1584
|
+
frameworkDirs.add(
|
|
1585
|
+
surface.kind === 'swift'
|
|
1586
|
+
? path.resolve(surface.interface, '../../../..')
|
|
1587
|
+
: path.resolve(surface.modulemap, '../../..'),
|
|
1588
|
+
)
|
|
1589
|
+
}
|
|
1590
|
+
} catch {
|
|
1591
|
+
// the target reports its artifact gap when visited below.
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1359
1594
|
const generatedToolchain = { ...toolchain, standinModules: modules }
|
|
1360
|
-
const
|
|
1595
|
+
const frameworks: NativeFrameworkInputs = {
|
|
1596
|
+
dirs: [...frameworkDirs].sort(),
|
|
1597
|
+
digest: createHash('sha256').update(frameworkInputs.sort().join('\0')).digest('hex'),
|
|
1598
|
+
}
|
|
1599
|
+
// another binary's module a swift interface imports: its stand-in is built
|
|
1600
|
+
// first and imported, as the vendor framework imports the other framework
|
|
1601
|
+
const siblings = new Map(
|
|
1602
|
+
binaries.map((binary) => [
|
|
1603
|
+
binary,
|
|
1604
|
+
new Set(
|
|
1605
|
+
[...(interfaceImports.get(binary) ?? [])].filter((module) => {
|
|
1606
|
+
const owner = byModule.get(module)
|
|
1607
|
+
return owner !== undefined && owner !== binary && !provided.has(module)
|
|
1608
|
+
}),
|
|
1609
|
+
),
|
|
1610
|
+
]),
|
|
1611
|
+
)
|
|
1361
1612
|
const prerequisites = new Set(
|
|
1362
|
-
binaries.flatMap((binary) =>
|
|
1363
|
-
(binary.headerDependencies ?? []).map((dependency) =>
|
|
1364
|
-
|
|
1613
|
+
binaries.flatMap((binary) => [
|
|
1614
|
+
...(binary.headerDependencies ?? []).map((dependency) =>
|
|
1615
|
+
swiftTargetModuleName(dependency.module),
|
|
1616
|
+
),
|
|
1617
|
+
...siblings.get(binary)!,
|
|
1618
|
+
]),
|
|
1365
1619
|
)
|
|
1366
1620
|
const visited = new Set<string>()
|
|
1367
1621
|
const visit = (binary: SwiftPackageBinary) => {
|
|
1368
1622
|
if (visited.has(binary.target)) return
|
|
1369
1623
|
visited.add(binary.target)
|
|
1370
|
-
for (const
|
|
1371
|
-
|
|
1624
|
+
for (const module of [
|
|
1625
|
+
...(binary.headerDependencies ?? []).map((dependency) =>
|
|
1626
|
+
swiftTargetModuleName(dependency.module),
|
|
1627
|
+
),
|
|
1628
|
+
...siblings.get(binary)!,
|
|
1629
|
+
]) {
|
|
1630
|
+
const target = byModule.get(module)
|
|
1372
1631
|
if (target) visit(target)
|
|
1373
1632
|
}
|
|
1374
|
-
const result = binaryStandins(
|
|
1633
|
+
const result = binaryStandins(
|
|
1634
|
+
binary,
|
|
1635
|
+
generatedToolchain,
|
|
1636
|
+
provided,
|
|
1637
|
+
behavior,
|
|
1638
|
+
frameworks,
|
|
1639
|
+
siblings.get(binary)!,
|
|
1640
|
+
)
|
|
1375
1641
|
if (typeof result === 'string') {
|
|
1376
1642
|
gaps.set(binary.target, result)
|
|
1377
1643
|
return
|