Hive
Parallelize XCFramework creation during cache warm
GitHub issue · Closed
Why is this needed?
tuist cache warm currently creates XCFramework artifacts serially after the platform-specific framework builds complete. In projects with many cacheable framework targets, this phase can become a significant wall-clock bottleneck even after the actual framework builds have finished.
In a large private project using Tuist 4.191.x, a full binary cache warm produced 1,039 stored artifacts, including 969 XCFrameworks. The measured phase breakdown included:
Binaries-Cache-iOS simulator 442.077s
Binaries-Cache-iOS device 447.776s
Binaries-Cache-macOS device 18.310s
Creating XCFrameworks 589.668s
Storing binaries 113.216s
Total 1843.715s
The XCFramework creation phase alone took roughly 9.8 minutes. Inspecting the implementation shows that CacheWarmCommandService.buildXCFrameworks iterates through cacheable framework targets with a serial for loop and invokes xcodebuild -create-xcframework once per target.
A controlled local experiment recreated the XCFramework creation phase with the same set of framework targets and Apple’s xcodebuild -create-xcframework command. The input set was derived from the current cache-warm framework artifacts in that project: 941 iOS framework targets with simulator and device slices available for XCFramework creation. Running the same inputs serially versus with a bounded concurrency of 4 produced:
input framework targets 941
serial create time 564.480s
parallel create time, limit 4 167.363s
serial successful outputs 941
parallel successful outputs 941
serial failures 0
parallel failures 0
This is not a perfect apples-to-apples benchmark of the full tuist cache warm pipeline because it isolates only the XCFramework creation phase, but it keeps Apple’s xcodebuild -create-xcframework in the loop and uses the same target set for both serial and parallel runs. The result suggests that bounded parallelism can significantly reduce wall-clock time for this phase.
A safer improvement would be to keep using xcodebuild -create-xcframework, but run multiple independent XCFramework creation operations concurrently with a bounded concurrency limit.
Steps to address the need
-
Update
CacheWarmCommandService.buildXCFrameworksto create independent XCFrameworks with bounded concurrency instead of the current serial loop.- Current code path:
cli/Sources/TuistKit/Commands/Cache/CacheWarmCommandService.swift - The per-target outputs are distinct:
temporaryDirectory/xcframeworks/<target>.xcframework - App Intents metadata copying should remain part of the same per-target operation.
- Current code path:
-
Reuse the existing concurrency helpers where possible.
Array.concurrentMap(maxConcurrentTasks:)already exists inTuistSupportand preserves input order.- Preserving output order keeps artifact storage behavior deterministic.
-
Use a conservative concurrency limit rather than unbounded concurrency.
- Spawning hundreds of
xcodebuildprocesses at once would likely overload the machine. - A small default such as 4, or an internal constant derived from available resources, would be a safer first step.
- Spawning hundreds of
-
Add or adjust tests to verify:
- All framework targets still produce
CacheGraphTargetBuiltArtifactentries. - Result ordering remains deterministic.
- App Intents metadata copying still happens for each generated XCFramework.
- Errors from any
xcodebuild -create-xcframeworkinvocation still fail the cache warm.
- All framework targets still produce
-
Optionally, as a separate cleanup, remove the duplicate
-allow-internal-distributionargument if maintainers agree.buildXCFrameworkscurrently adds it to the arguments.XcodeBuildController.createXCFrameworkalso appends it.- This is not the main performance improvement and can be handled separately if preferred.
No GitHub comments yet.