[build-tools] - support Xcode DerivedData pod products caching for iOS builds#3491
[build-tools] - support Xcode DerivedData pod products caching for iOS builds#3491AbbanMustafa wants to merge 11 commits intomainfrom
Conversation
|
Subscribed to pull request
Generated by CodeMention |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3491 +/- ##
==========================================
+ Coverage 53.39% 53.44% +0.06%
==========================================
Files 813 816 +3
Lines 34438 34783 +345
Branches 7151 7217 +66
==========================================
+ Hits 18384 18587 +203
- Misses 15972 16115 +143
+ Partials 82 81 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
⏩ The changelog entry check has been skipped since the "no changelog" label is present. |
sjchmiela
left a comment
There was a problem hiding this comment.
Did you see / try:
- https://guides.cocoapods.org/plugins/pre-compiling-dependencies.html + https://levelup.gitconnected.com/reduce-azure-pipelines-xcode-build-time-by-80-through-cocoapods-caching-5c2de0f657df
- https://engineering.atspotify.com/2021/11/introducing-xcremotecache-the-ios-remote-caching-tool-that-cut-our-clean-build-times-by-70
Can you please add comments explaining the logic / subjects / actions the code is doing? There's a lot to understand here and magic prefixes and everything and making it clearer will also maybe make it clearer to review
|
|
||
| export async function generateXcodeCacheKeyAsync( | ||
| workingDirectory: string, | ||
| simulator?: boolean |
There was a problem hiding this comment.
Is simulator cache helpful for device build and/or vice versa? It seems it's not based on PR descirption. Let's make the parameter required and an inline enumerator "simulator" | "device" or sth like that.
|
|
||
| import { findPackagerRootDir } from './packageManager'; | ||
|
|
||
| export const XCODE_CACHE_KEY_PREFIX = 'ios-xcode-cache-'; |
There was a problem hiding this comment.
Let's not export it like that if it should never restore "just" ios-xcode-cache- cache?
| logger.info(`Rewrote paths in ${patchCount} modulemap files`); | ||
| } | ||
|
|
||
| const PATCH_RUBY_SCRIPT = ` |
There was a problem hiding this comment.
Is this achievable using Expo config plugins code?
|
I'll also let myself add @lukmccall as a reviewer — he has much more experience in the area. I also wonder how does https://github.com/software-mansion/rnrepo do it for the recently added iOS support. If this pull request's main thing is to cache Pod artifacts and they do build Pod artifacts for reuse… |
lukmccall
left a comment
There was a problem hiding this comment.
Are we sure that we're not leaking any personal information by caching DerivedData? I'm not sure if this directory was intended to be cached.
| const variant = simulator ? 'sim' : 'device'; | ||
|
|
||
| try { | ||
| return `${XCODE_CACHE_KEY_PREFIX}${variant}-${hashFiles([lockPath])}`; |
There was a problem hiding this comment.
The lockfile probably doesn't change if we change the XCode version. So, we probably need to include it in the key.
| const PATCH_RUBY_SCRIPT = ` | ||
| require 'xcodeproj' | ||
|
|
||
| project = Xcodeproj::Project.open('ios/Pods/Pods.xcodeproj') |
There was a problem hiding this comment.
Consider searching for the xcodeproj rather than relying on the hardcoded path.
Oh so this is not going to be public, this cache is scoped per-app |

Why
iOS builds currently recompile all CocoaPods from scratch on every build. Unlike local development where Xcode's DerivedData persists compiled products between builds, CI builds start with a clean DerivedData every time.
The xcodebuild step spends the majority of its time rebuilding pod dependencies that haven't changed between builds. This adds Xcode build product caching to skip that redundant recompilation. Gated behind
EAS_XCODE_CACHE=1.How
Cache pre-built pod products (.a l ibraries, .modulemap files, headers) from DerivedData after a successful build, keyed by lockfile hash. On subsequent builds, restore the cached products and patch the Xcodeproject to skip pod recompilation.
Restore (RESTORE_CACHE): Extract cached products to
/tmp/pods-cache/and rewrite absolute paths in.modulemapfiles. Products live outside DerivedData becausexcodebuild archivewipesArchiveIntermediates/at the start of each run.Patch (INSTALL_PODS, after pod install): Placing pre-built products on disk isn't enough. Xcode still sees pod targets in
Pods.xcodeprojand will rebuild them. Provide a Ruby script removes non-umbrella pod targets fromthe project entirely, then patches
PODS_CONFIGURATION_BUILD_DIRin the xcconfig files to point at/tmp/pods-cache/so the linker resolves to cached .a files instead of empty DerivedData.Save (SAVE_CACHE): Locate build products in
ArchiveIntermediates/.../BuildProductsPath/Release-*(archive) orBuild/Products/Release-*(simulator) and upload. derived_data_path is set to ./build in the Gymfile soproducts land in a known location. Each save replaces the entire cache, so stale products from removed pods are naturally pruned.
Cache key is
ios-xcode-cache-{device|sim}-{lockfile_hash}— separate keys for device (Release-iphoneos, arm64) and simulator (Debug-iphonesimulator, x86_64/arm64) builds to prevent architecture mismatches.Performance: Archive builds go from 🙌~3 min to ~30 sec on cache hit (6x speedup)🙌
Test Plan