Целевая аудитория: инженеры iOS и кросс-платформенных команд, а также сопровождающие CI/CD, которые запускают xcodebuild на удалённых узлах Mac и борются за предсказуемое время прогона и стабильность раннеров.

Ключевые термины: удалённый Mac, кеш компиляции Xcode, Derived Data, iOS CI, ускорение сборки. Ниже — сводная таблица условий попадания в кеш, политика прогрева и очистки, матрица «clean build vs параметры» с копируемыми командами и FAQ по откату и заполнению диска. Связанные материалы: решения ускорения macOS CI, матрица Submodule и LFS. Навигация по сайту: главная, каталог статей блога.

Принцип кеша и условия попадания: сводная таблица

Инкрементальная сборка Xcode опирается на согласованность пути Derived Data, версии инструментов, набора флагов компиляции и идентичности зависимостей. На удалённом Mac чаще всего «ломают» cache hit эфемерные каталоги, смена -destination без учёта в ключе кеша и обновление SwiftPM без закреплённого Package.resolved. Зафиксируйте в runbook, какие сигналы входят в ключ восстановления артефакта между джобами.

Фактор Влияние на cache hit Что закрепить в ключе / конфиге
Версия Xcode / CLT Смена toolchain сбрасывает совместимость модулей xcodebuild -version, билд-агент; отдельный префикс Derived Data на мажор
Путь Derived Data Один и тот же -derivedDataPath между прогонами одной ветки Общий том + подкаталог $JOB_CACHE/xcode/$(shasum Package.resolved Podfile.lock)
SwiftPM Без закреплённого lock частые промахи по исходникам пакетов Хеш Package.resolved + -clonedSourcePackagesDirPath
CocoaPods Изменение checksum Pods меняет заголовки и модули Хеш Podfile.lock + версия Ruby/Pods
Набор GCC_PREPROCESSOR_DEFINITIONS / SWIFT_ACTIVE_COMPILATION_CONDITIONS Любое расхождение даёт новый набор объектных файлов Сериализация активных конфигураций в ключ или отдельные схемы CI
Destination (симулятор / устройство) Разные SDK и архитектуры — разные кеши Отдельные префиксы для iphonesimulator vs iphoneos

Для наблюдаемости включите в лог джобы короткий блок диагностики: версию Xcode, путь Derived Data, хеши lock-файлов и выбранный -destination. Это ускоряет разбор «внезапных» холодных сборок на iOS CI.

С точки зрения CI/CD и стабильности узла полезно считать долю инкрементальных прогонов и медиану времени этапа компиляции: резкий рост при неизменном коде почти всегда указывает на смену ключа кеша, конкуренцию за диск или смешение схем в одном префиксе Derived Data.

Прогрев удалённого узла и политика очистки

Стабильный удалённый Mac в роли CI-ноды выигрывает от разделения трёх слоёв: кеш Git (см. стратегию кеша Git и npm), каталог SwiftPM и Derived Data. Прогрев — это не «магический» первый запуск, а воспроизводимая последовательность с теми же флагами, что и боевая джоба.

Параметры окружения и пути (пример)
export DERIVED_DATA_PATH="/Volumes/CI/derived/${XCODE_VERSION}/${LOCK_HASH}"
export SPM_CLONE_DIR="/Volumes/CI/spm/${LOCK_HASH}"
mkdir -p "$DERIVED_DATA_PATH" "$SPM_CLONE_DIR"

xcodebuild -resolvePackageDependencies \
  -scheme "YourApp" \
  -clonedSourcePackagesDirPath "$SPM_CLONE_DIR" \
  -derivedDataPath "$DERIVED_DATA_PATH"

xcodebuild build \
  -scheme "YourApp" \
  -destination "platform=iOS Simulator,name=iPhone 16,OS=18.2" \
  -derivedDataPath "$DERIVED_DATA_PATH" \
  -clonedSourcePackagesDirPath "$SPM_CLONE_DIR" \
  COMPILER_INDEX_STORE_ENABLE=NO

COMPILER_INDEX_STORE_ENABLE=NO часто снижает объём записи на диск в CI, где индексатор Xcode не нужен; проверьте, что это допустимо для ваших статических анализов. Политика очистки: удаляйте сначала неиспользуемые префиксы по возрасту (например > 14 дней) и по свободному месту. Ориентир для мониторинга — см. следующий раздел FAQ; до критического порога используйте мягкое удаление, а не полный rm -rf ~/Library/Developer/Xcode/DerivedData на общих раннерах.

  • Ночной прогрев: после merge в основную ветку выполните разрешение пакетов + build эталонной схемы и зафиксируйте снимок каталога или rsync на общий том.
  • Блокировка: при параллельных джобах на одном томе используйте файловые lock-и или отдельные подкаталоги на BUILD_NUMBER, чтобы не портить кеш.
  • Проверка диска перед джобой: df -h "$DERIVED_DATA_PATH" — прервите постановку в очередь, если ниже мягкого порога.

Компромисс параметров и clean build

Clean build гарантирует отсутствие «залипших» объектных файлов, но на удалённом Mac обычно стоит дороже 5–15 минут на крупном приложении. Используйте его точечно, а повседневную матрицу стройте на инкременте с жёстко заданным -derivedDataPath.

Сценарий Рекомендация Исполняемый ориентир
Регрессии после обновления Xcode Один полный clean на эталонном пути, затем снимок кеша xcodebuild clean build + новый префикс DERIVED_DATA_PATH
Быстрая проверка PR Инкремент + фиксированный симулятор Без clean; тот же -destination
Флейки SwiftPM / модули Таргетированный сброс + повтор Удалить только SourcePackages и кеш схемы; затем -resolvePackageDependencies
Анализ без подписи Сократить побочные артефакты CODE_SIGNING_ALLOWED=NO (если допустимо этапом)

Дополнительные исполняемые переменные, которые часто задают в shell-обёртке раннера: IDEBuildOperationMaxNumberOfConcurrentCompileTasks (ограничение параллельных задач компиляции под число ядер узла), SWIFT_EXEC (только при пинованном toolchain) и RCT_NO_LAUNCH_PACKAGER=1 для React Native — проверяйте релевантность под ваш стек, чтобы не размножать скрытые ветви кеша.

1

Согласованность аргументов. Любой дрейф в ONLY_ACTIVE_ARCH, DEBUG_INFORMATION_FORMAT или включении биткода исторически менял набор объектников; сверяйте .xcconfig CI с локальными пресетами команды.

2

Матрица джоб. Держите «быструю» линию на одном симуляторе и одной схеме; тяжёлые комбинации устройств выносите в ночной слот с отдельным ключом кеша, чтобы не вытеснять основной кеш компиляции Xcode.

FAQ: отказоустойчивость и пороги заполнения диска

Мягкий порог: если свободно < 25–30% тома с Derived Data или < 35 ГБ абсолютно — запланируйте фоновую уборку старых префиксов и уведомление в чат CI. Жёсткий порог: < 12–15% или < 18 ГБ — остановите постановку новых джоб, завершите текущие, выполните контролируемую очистку и один эталонный прогрев.

Откат после порчи кеша: пометьте префикс как bad (например переименуйте в .corrupt.<timestamp>), запустите джобу с пустым DERIVED_DATA_PATH, зафиксируйте успешный прогон как новый эталон. При повторении той же ошибке линковки добавьте в pipeline флаг «игнорировать восстановление кеша» для данной ветки на один прогон.

Сеть и диск: длинные копирования снимков Derived Data по NFS без достаточного кеша на клиенте могут съедать выигрыш; измеряйте p95 этапа «restore cache» и сравнивайте с холодной сборкой. Подробнее о стабильности загрузок и повторах см. FAQ по Git, Homebrew и npm.

Итог

Высокая доля попаданий в кеш компиляции Xcode на удалённом Mac достигается не «включением кеша», а согласованностью Derived Data, lock-файлов, -destination и политики прогрева. Clean build оставьте для смены toolchain и аварий; повседневный iOS CI стройте на инкременте с измеримыми порогами диска и явным откатом при порче артефактов.

CTA (внутренние страницы без логина): Тарифы аренды удалённого Mac · Оформить аренду Mac для CI · Центр помощи MacPull · Главная · Все статьи блога. Якорные формулировки для ссылок с других страниц: «Матрица кеша Xcode для iOS CI», «Прогрев Derived Data на удалённом Mac», «Пороги диска для раннера Xcode».

Удалённый Mac под стабильный iOS CI

Нативный macOS, предсказуемый диск и полный контроль над кешем Xcode — оформите аренду или откройте тарифы.

Быстрая выдача узла
Контроль Derived Data
iOS и Xcode