# Кэш Xcode {#xcode-cache}

Tuist поддерживает кэш компиляции Xcode, который позволяет командам обмениваться артефактами компиляции, используя возможности кэширования системы сборки.

Кэш Xcode появился в Xcode 26. Его также называют кэшем сборки Xcode; он повторно использует артефакты компиляции, ключом для которых служат входные данные, а удалённый кэш Tuist делает эти артефакты доступными для обмена между машинами.

> [!TIP]
> **Объедините с кэшем модулей**
>
> Кэш Xcode и <.localized_link href="/guides/features/cache/module-cache">кэш модулей</.localized_link> работают на разных уровнях детализации и дополняют друг друга. Кэш модулей заменяет целые модули предварительно собранными `.xcframework` до начала сборки, тогда как кэш Xcode повторно использует результаты компиляции во время сборки.

> [!TIP]
> **На машинах разработчиков сохраняйте `CompilationCache.noindex` при очистке**
>
> По умолчанию хранилище кэша компиляции находится внутри `DerivedData`, поэтому удаление `DerivedData` удаляет его вместе с продуктами сборки. На машине разработчика лучше удалять только продукты сборки: повторная сборка затем воспроизводит их из хранилища на диске без дополнительных загрузок.

## Настройка {#setup}

Если у вас ещё нет учётной записи и проекта Tuist, вы можете создать их, выполнив команду:

```bash
tuist init
```

После того как у вас появится файл `Tuist.swift`, ссылается на ваш `fullHandle`, вы можете настроить кэширование для своего проекта, выполнив команду:

```bash
tuist setup cache
```

Эта команда создаёт [LaunchAgent](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html) для запуска локального сервиса кэша при старте, который система сборки Swift [build system](https://github.com/swiftlang/swift-build) использует для обмена артефактами компиляции. Запустите её сначала на своей машине разработчика, а также в рамках настройки каждого задания CI.

Чтобы настроить кэш в CI, убедитесь, что вы <.localized_link href="/guides/integrations/continuous-integration#authentication">аутентифицированы</.localized_link>.

### Обновление компонентов кэша {#updating-the-cache-components}

Прокси-сервер кэша использует стабильный лаунчер вместо пути, привязанного к установке Tuist, которая последней выполняла настройку. После установки `tuist setup cache` и включённая для кэша команда `tuist generate` переводят рабочий таргет на более новые выпуски Tuist. Проекты, привязанные к старой версии Tuist, поэтому не понижают версию общего прокси. Генерация только обновляет существующий таргет лаунчера: она не устанавливает сервис, не выполняет аутентификацию, не заменяет плагин и не перезапускает прокси. Пользовательские переопределения плагина, прокси, сокета или реестра пропускают автоматическое продвижение.

Запущенный прокси принимает новый таргет только после как минимум 30 секунд без запросов к кэшу, когда нет активных запросов или фоновых задач и его очереди публикации опустошены. Затем он завершается, и launchd запускает выбранный CLI, сохраняя аргументы сервиса и среду учётных данных. Только прокси, который действительно принимает таргет, атомарно обновляет плагин на диске из своего бандла; настройка не устанавливает более новый плагин, пока старый прокси всё ещё опустошает очереди. Если установленный плагин отсутствует, явная настройка в режиме простоя перезапускает выбранный прокси для повторной попытки обновления. По-прежнему только один прокси владеет реестром и очередями. Недоступный таргет или неопустошённые загрузки откладывают переключение, а не прерывают активные запросы. Обновление учётных данных следует за выбранным CLI ещё до переключения, поэтому удаление старой установки CLI не оставляет загрузки в ожидании опустошения.

Существующая установка, созданная до появления стабильного лаунчера, требует одной явной миграции. Выполните следующее, когда не запущены сборки:

```bash
tuist setup cache
```

После этой миграции достаточно обновить Tuist и выполнить обычную команду `tuist generate`, чтобы продвинуть прокси и установленный плагин; вам не нужно заново запускать настройку для каждого выпуска CLI. Явная настройка всё ещё нужна, чтобы выбрать другой Xcode, включая Xcode, обновлённый по тому же пути. Настройка может заменить общий сервис при изменении его конфигурации, поэтому сначала дождитесь завершения всех сборок на машине. Прокси поддерживает как предыдущий, так и текущий протокол плагина, поэтому совместимый плагин, уже загруженный в Xcode, продолжает работать после обновления прокси. Полностью закройте и снова откройте Xcode, чтобы загрузить новейший плагин, но совместимый загруженный плагин не требует немедленного перезапуска. Перегенерируйте проекты, если выпуск изменяет сгенерированные настройки сборки.

Оставьте выбранную установку Tuist доступной: лаунчер использует её для запуска, конфигурации и обновления учётных данных. Старые установки можно удалить после того, как лаунчер продвинется. Если выбранный исполняемый файл был удалён или больше не является исполняемым, `tuist setup cache` может восстановить таргет, используя доступную установку, даже более старый выпуск, без предварительного демонтажа кэша. Стабильные алиасы исполняемых файлов сохраняются при обновлениях менеджера пакетов; символические ссылки разрешаются только при сравнении идентичности установки. При запуске прокси записывает фактически запущенную версию, включая обновления на месте или преднамеренные откаты, сохраняя при этом самую высокую использованную версию, чтобы предотвратить переключение рабочей установки несвязанными старыми чекаутами.

CLI, собранные из исходников без версии выпуска и с явными настройками `TUIST_CAS_PLUGIN_PATH` или `TUIST_CAS_PROXY_PATH`, используют явную конфигурацию запуска вместо автоматического выбора версии. Повторно запустите настройку после пересборки этих компонентов. Настройка проверяет их актуальность и отключает управляемое продвижение таргета только после того, как замена будет готова.

`tuist teardown cache` останавливает сервис перед удалением таргета лаунчера, сохраняя при этом стабильный плагин для существующих проектов. Если остановка сервиса не удаётся, его лаунчер остаётся доступным для перезапуска и повторной попытки демонтажа. Генерация не может воссоздать сервис после успешного демонтажа.

### Настройка параметров сборки Xcode {#configure-xcode-build-settings}

Для существующего проекта Xcode скопируйте параметры сборки, выведенные командой `tuist setup cache`, в настройки сборки вашего проекта или в существующий файл `.xcconfig`. Команда выводит конфигурацию для вашей учётной записи; она не генерирует файл конфигурации и не редактирует ваш проект Xcode. Сохраняйте `$(inherited)` при расширении `OTHER_SWIFT_FLAGS`, чтобы другие параметры компилятора сохранились.

Параметры включают:

```
COMPILATION_CACHE_ENABLE_CACHING = YES
COMPILATION_CACHE_ENABLE_PLUGIN = YES
COMPILATION_CACHE_PLUGIN_PATH = $HOME/.local/state/tuist/libtuist_cas_plugin.dylib
COMPILATION_CACHE_REMOTE_SERVICE_PATH = $HOME/.local/state/tuist/cas-proxy.sock
COMPILATION_CACHE_ENABLE_DETACHED_KEY_QUERIES = YES
COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS = YES
OTHER_SWIFT_FLAGS = $(inherited) -cas-plugin-option tuist-instance=your-org/your-project
```

Обратите внимание, что `COMPILATION_CACHE_ENABLE_PLUGIN`, `COMPILATION_CACHE_PLUGIN_PATH`, `COMPILATION_CACHE_REMOTE_SERVICE_PATH` и `COMPILATION_CACHE_ENABLE_DETACHED_KEY_QUERIES` необходимо добавить как **пользовательские параметры сборки**, поскольку они не отображаются напрямую в интерфейсе настроек сборки Xcode.

> [!NOTE]
> **Путь к плагину**
>
> `libtuist_cas_plugin.dylib` — это плагин кэша компиляции, который поставляется вместе с Tuist и находится рядом с исполняемым файлом `tuist`. Команда `tuist setup cache` копирует его в `$HOME/.local/state/tuist/libtuist_cas_plugin.dylib`, а параметр `COMPILATION_CACHE_PLUGIN_PATH` указывает на эту копию. Путь одинаков на каждом компьютере и не меняется при обновлении Tuist, поэтому вы можете зафиксировать эту настройку в репозитории проекта. Настройка и недавно запущенный прокси обновляют копию из выбранного бандла Tuist; запуск настройки из более старой версии кода не понижает версию более нового плагина.

> [!NOTE]
> **Один сокет для каждого проекта**
>
> Команда `tuist setup cache` устанавливает один кэш-прокси на компьютер, поэтому каждый проект использует один и тот же путь `COMPILATION_CACHE_REMOTE_SERVICE_PATH`. Проект идентифицируется опцией плагина `tuist-instance`.

> [!IMPORTANT]
> **`COMPILATION_CACHE_REMOTE_SERVICE_PATH` обеспечивает совместное использование C и Objective-C**
>
> Эту настройку легко воспринять как «место расположения сервиса кэша» и считать её необязательной. Однако именно она определяет, будут ли вообще совместно использоваться файлы C, Objective-C, предварительно скомпилированные модули и заголовки: система сборки выполняет их кэширование только при наличии настроенного удалённого сервиса кэша. Если её убрать, компиляции Swift всё равно будут разделяться, но каждый файл C/Objective-C и каждый модуль будут перекомпилироваться на любом компьютере, где проект ранее не собирался.

> [!NOTE]
> **Параллельные запросы к кэшу**
>
> Параметр `COMPILATION_CACHE_ENABLE_DETACHED_KEY_QUERIES` выполняет удалённые запросы к кэшу для каждой компиляции параллельно с остальной частью сборки, вместо того чтобы выполнять их по несколько за раз на исполнительных потоках сборки. Сборки, которые часто пропускают кэш или восстанавливают много компиляций из удалённого кэша, завершаются быстрее.

Вы также можете указать эти параметры при запуске `xcodebuild`, добавив следующие флаги, например:

```
xcodebuild build -project YourProject.xcodeproj -scheme YourScheme \
    COMPILATION_CACHE_ENABLE_CACHING=YES \
    COMPILATION_CACHE_ENABLE_PLUGIN=YES \
    COMPILATION_CACHE_PLUGIN_PATH=$HOME/.local/state/tuist/libtuist_cas_plugin.dylib \
    COMPILATION_CACHE_REMOTE_SERVICE_PATH=$HOME/.local/state/tuist/cas-proxy.sock \
    COMPILATION_CACHE_ENABLE_DETACHED_KEY_QUERIES=YES \
    COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS=YES \
    'OTHER_SWIFT_FLAGS=$(inherited) -cas-plugin-option tuist-instance=your-org/your-project'
```

> [!NOTE]
> **Сопоставление префиксов в Xcode 27 и новее**
>
> В Xcode 27 и новее команда `tuist setup cache` также выводит параметры `SWIFT_ENABLE_PREFIX_MAPPING`, `SWIFT_ENABLE_PROJECT_PREFIX_MAPPING`, `CLANG_ENABLE_PREFIX_MAPPING` и `CLANG_ENABLE_PROJECT_PREFIX_MAPPING`. Они делают ключи кэша компиляции независимыми от расположения проекта и каталога `DerivedData`. Добавьте их как пользовательские параметры сборки. Включение этих параметров изменяет все ключи кэша, поэтому следующая сборка снова заполнит кэш. Команда `tuist generate` устанавливает их автоматически, когда включён параметр `enableCaching`.
>
> Компилятор также записывает сопоставленные пути в данные покрытия кода, и Xcode не может их разрешить, поэтому отчёт о покрытии будет исключать все исходные файлы, скомпилированные с сопоставлением префиксов. Выведенные параметры, а также параметры `TUIST_PREFIX_MAPPING_FOR_COVERAGE_*`, отключают сопоставление префиксов в сборках, собирающих данные о покрытии кода. То же самое делает команда `tuist generate`. Такие сборки всё ещё используют кэш компиляции, но их ключи кэша зависят от путей проекта и `DerivedData`.
>
> При передаче этих параметров в `xcodebuild` через командную строку заключайте значения, содержащие `$(...)`, в одинарные кавычки, как показано выше для `OTHER_SWIFT_FLAGS`. Иначе оболочка расширит их до пустых строк, и сопоставление префиксов будет отключено:
>
> ```
> xcodebuild build -project YourProject.xcodeproj -scheme YourScheme \
>     'SWIFT_ENABLE_PREFIX_MAPPING=$(TUIST_PREFIX_MAPPING_FOR_COVERAGE_$(CLANG_COVERAGE_MAPPING))' \
>     SWIFT_ENABLE_PROJECT_PREFIX_MAPPING=YES \
>     'CLANG_ENABLE_PREFIX_MAPPING=$(TUIST_PREFIX_MAPPING_FOR_COVERAGE_$(CLANG_COVERAGE_MAPPING))' \
>     CLANG_ENABLE_PROJECT_PREFIX_MAPPING=YES \
>     TUIST_PREFIX_MAPPING_FOR_COVERAGE_=YES \
>     TUIST_PREFIX_MAPPING_FOR_COVERAGE_NO=YES \
>     TUIST_PREFIX_MAPPING_FOR_COVERAGE_YES=NO
> ```

> [!NOTE]
> **Сгенерированные проекты**
>
> Если ваш проект генерируется Tuist, вручную задавать эти параметры не нужно.
>
> В этом случае достаточно добавить `enableCaching: true` в ваш файл `Tuist.swift`:
> ```swift
> import ProjectDescription
>
> let tuist = Tuist(
>     fullHandle: "your-org/your-project",
>     project: .tuist(
>         generationOptions: .options(
>             enableCaching: true
>         )
>     )
> )
> ```

### Покрытие кода с сопоставлением префиксов {#coverage-with-prefix-mapping}

По умолчанию сгенерированные проекты отключают сопоставление префиксов для сборок с покрытием кода, чтобы отчеты о покрытии Xcode и инструмент `xccov` работали корректно. Вы можете включить его, чтобы компиляции для покрытия кода можно было разделять между разными версиями кода:

```swift
let tuist = Tuist(
    project: .tuist(
        generationOptions: .options(
            enableCaching: true,
            coverage: .coverage(prefixMapping: true)
        )
    )
)
```

Переменная окружения `TUIST_COVERAGE_PREFIX_MAPPING` (`1` или `0`) имеет приоритет над параметром `prefixMapping`. Эта опция применяется в Xcode 27 и новее и требует включения `enableCaching`. Загрузка результатов покрытия через `tuist test` поддерживает её: Tuist измеряет выполнение с помощью `llvm-cov`, который читает исходные файлы с сопоставленными путями и связывает их с файлами вашего репозитория. Собственный отчёт о покрытии Xcode и инструмент `xccov` всё ещё могут исключать эти исходные файлы, как и загрузка, которая возвращается к отчёту `xccov` из пакета результатов, если экспорт `llvm-cov` не удался. Сопоставленные значения `#filePath` также могут влиять на тесты, которые locate фикстуры относительно исходных файлов; вместо этого разрешайте фикстуры через явные пути checkout во время выполнения. Если вы обрабатываете данные покрытия самостоятельно, сопоставляйте каждый инструментированный бинарный файл с файлом `$(TARGET_TEMP_DIR)/compilation-prefix-map.json` его таргета, который отображает виртуальные префиксы обратно в локальные каталоги. Не используйте карту одного таргета для всех бинарных файлов, если включено сопоставление префиксов для каждого проекта.

Параметры префиксов покрытия участвуют в хешах бинарного кэша и селективного тестирования, поскольку они контролируют пути, записываемые в артефакты покрытия. Изменение этой опции или установка другого значения `TUIST_COVERAGE_PREFIX_MAPPING` делает эти хеши недействительными даже для обычных сборок. Сохраняйте значение согласованным между разработчиками и задачами CI, если они должны использовать общие бинарные кэши и результаты селективного тестирования.

### Отладка сгенерированных проектов {#debugging-generated-projects}

Восстановленным нативным модулям нужны связанные отладочные данные, а также доступ к кэшу компиляции. Tuist подготавливает модули Debug и Release, добавляя dSYM и метаданные идентичности источников для каждого слайса, затем проверяет метаданные против объявленных источников потребителя перед заменой таргета. При отсутствии или несовместимости метаданных сохраняются источники этого таргета. Источники, сгенерированные скриптами через `.generated(...)`, имеют отпечатки деклараций, а не проверяемые контрольные суммы содержимого, поэтому такие таргеты остаются собранными из исходников и не публикуются в кэше нативных модулей. Сгенерированные аксессоры ресурсов с реальными контрольными суммами содержимого остаются пригодными для кэширования. Неподдерживаемые отладочные данные пропускают публикацию затронутого таргета, не блокируя несвязанные продукты; мутация источников и отмена всё ещё приводят к сбою подготовки. Формат кэша меняется, поэтому артефакты, подготовленные старыми версиями, требуют повторной подготовки.

Для проверенных замен Tuist готовит перемещения источников в plist-файлах UUID dSYM, принадлежащих потребителю, и связывает отладочные компаньоны для статического кэшированного кода. Он не перезаписывает кэшированные бинарные файлы и не устанавливает пути источников производителя в постоянную глобальную карту источников LLDB. Явные инициализаторы отладчика и настройки загрузчика модулей остаются авторитетными. Отладочные символы и перемещение источников не исправляют доступ к файлам во время выполнения, зависящий от путей к источникам, или нативные отчёты о покрытии Xcode; выбор варианта покрытия и экспорт LLVM остаются отдельными функциями.

При включённом `enableCaching: true` Tuist настраивает карты источников LLDB для действий Run и Test. Если у действия есть собственный инициализатор LLDB, Tuist сначала записывает разрешённую карту источников, а затем загружает пользовательский инициализатор, чтобы он мог расширить или переопределить карту. В противном случае он загружает `~/.lldbinit-Xcode`, если файл существует, с откатом к `~/.lldbinit`, прежде чем заменить карту источников. Загружается только один домашний файл, что восстанавливает настройки отладчика для каждого пользователя без двойной загрузки. Замена удаляет устаревшие сопоставления из предыдущих запусков и имеет приоритет над картами источников из домашних файлов; поместите записи карты источников, которые должны сохраняться, в пользовательский инициализатор действия. Остальные настройки домашнего файла сохраняются. Специфичные для кэша пути поиска модулей, настройки загрузчика и флаги Clang от Tuist применяются afterwards и имеют приоритет над пользовательскими значениями для этих настроек. Ошибки домашнего файла остаются видимыми, не останавливая загрузку последующих команд, и команды не выводятся в консоль. Это сохранение инициализатора также применяется, когда Tuist настраивает отладку для бинарных файлов, восстановленных из кэша модулей, даже без `enableCaching` и в более ранних версиях Xcode.

В Xcode 27 и новее сгенерированные проекты оставляют отключёнными попроектовые префиксные сопоставления Xcode (`SWIFT_ENABLE_PROJECT_PREFIX_MAPPING` и `CLANG_ENABLE_PROJECT_PREFIX_MAPPING`), если проект явно их не задаёт. Их префиксы, такие как `/^src`, обозначают разные директории в каждом проекте, и LLDB разрешает их только относительно проекта отлаживаемой цели. Вместо этого источники записываются под общими для рабочей области префиксами: `/^root` для корневой директории Tuist, `/^spm` для временной директории пакета Swift и `/^intermediates` и `/^products` для результатов сборки. Каждый из них обозначает одну и ту же директорию в каждом проекте, поэтому точки останова корректно разрешаются в источниках из любого проекта рабочей области.

Пути за пределами корневого каталога Tuist не сопоставляются. Ключи кэша проекта, находящегося за пределами корня, зависят от того, где он извлечён, поэтому другие извлечения и машины не попадут в кэш для него. Чтобы сделать его ключи независимыми от расположения извлечения, включите попроектовые сопоставления в манифесте этого проекта:

```swift
let checkoutIndependentSettings = Settings.settings(base: [
    "SWIFT_ENABLE_PROJECT_PREFIX_MAPPING": "YES",
    "CLANG_ENABLE_PROJECT_PREFIX_MAPPING": "YES",
])
```

Передайте эти настройки этому `Project`. При отладке цели из другого проекта LLDB тогда не сможет найти источники этого проекта. Настройки базового уровня проекта в манифесте имеют приоритет над значениями xcconfig на уровне проекта, поэтому устанавливайте их непосредственно в манифесте.

Изменение этих настроек меняет ключи кэша компиляции, хэши бинарного кэша и хэши выборочного тестирования, поэтому эти кэши нужно снова прогреть. Сохраняйте единообразие выбора во всей команде.

### Политика выгрузки в кэш {#cache-upload-policy}

По умолчанию сервис кэша как скачивает, так и выгружает артефакты в удалённый кэш. Вы можете управлять этим с помощью опции `xcodeCache` в файле `Tuist.swift`, чтобы включить режим только для чтения, при котором артефакты скачиваются, но никогда не выгружаются:

```swift
import ProjectDescription

let tuist = Tuist(
    fullHandle: "your-org/your-project",
    xcodeCache: .xcodeCache(
        upload: false
    ),
    project: .tuist(
        generationOptions: .options(
            enableCaching: true
        )
    )
)
```

Распространённая практика — выгружать артефакты только из CI, где сборки воспроизводимы, сохраняя локальные среды в режиме только для чтения. Этого можно добиться, используя `Environment.isCI`, который проверяет наличие переменной окружения `CI`, устанавливаемой большинством провайдеров CI:

```swift
import ProjectDescription

let tuist = Tuist(
    fullHandle: "your-org/your-project",
    xcodeCache: .xcodeCache(
        upload: Environment.isCI
    ),
    project: .tuist(
        generationOptions: .options(
            enableCaching: true
        )
    )
)
```

При такой настройке локальные сборки получают преимущество от кэшированных артефактов без выгрузки, тогда как сборки в CI заполняют кэш для остальной части команды.

Политика выгрузки записывается для каждого проекта на машине, которая запускает `tuist setup cache`. Чтобы изменить её, обновите `upload` и снова запустите `tuist setup cache`, а также `tuist generate`, если Tuist генерирует ваш проект. Последующие выгрузки будут следовать новой политике без перезапуска кэша на этой машине. Задачи для одного проекта, выполняющиеся одновременно на одной машине, используют общую политику, поэтому наиболее недавний вызов `tuist setup cache` определяет её для всех них.

### Ограничение размера хранилища {#store-size-limit}

Хранилище кэша компиляции растёт с каждой сборкой. Чтобы ограничить размер хранилищ проекта, установите `storeSizeLimit` в вашем файле `Tuist.swift`:

```swift
import ProjectDescription

let tuist = Tuist(
    fullHandle: "your-org/your-project",
    xcodeCache: .xcodeCache(
        storeSizeLimit: .gigabytes(20)
    ),
    project: .tuist(
        generationOptions: .options(
            enableCaching: true
        )
    )
)
```

Пока ни одна сборка не выполняется, Tuist проверяет каждое хранилище проекта каждые 10 минут. Он удаляет самые старые кэшированные выходные данные хранилища, как только новые сборки запишут около половины лимита, так что хранилище стабилизируется примерно на уровне лимита. Во время выполнения сборок хранилище может превышать лимит, а хранилище, которое уже было больше лимита в момент его установки, уменьшится, когда новые сборки запишут соответствующий объём данных. Когда несколько проектов используют одно хранилище, как это происходит при расположении по умолчанию, применяется наименьший из их лимитов. Лимит применяется на каждой машине, где вы запускаете `tuist setup cache`, поэтому после изменения лимита запустите команду снова.

### Хэши кэша модулей {#module-cache-hashes}

Настройки кэша компиляции не входят в состав <.localized_link href="/guides/features/projects/hashing">хэшей кэша модулей</.localized_link>. Tuist исключает из хэша каждую настройку сборки `COMPILATION_CACHE_*` и каждый флаг `-cas-plugin-option` со его значением. Включение или отключение `enableCaching` или изменение политики выгрузки сохраняет хэши ваших целей, поэтому бинарные файлы <.localized_link href="/guides/features/cache/module-cache">кэша модулей</.localized_link>, которые вы уже прогрели, остаются действительными. Вы можете сравнивать сборки с кэшем Xcode и без него, используя один и тот же кэш модулей.

> [!NOTE]
> **Настройки префиксного сопоставления хэшируются**
>
> В Xcode 27 и новее `enableCaching: true` также устанавливает `SWIFT_ENABLE_PREFIX_MAPPING`, `SWIFT_ENABLE_PROJECT_PREFIX_MAPPING`, `CLANG_ENABLE_PREFIX_MAPPING`, `CLANG_ENABLE_PROJECT_PREFIX_MAPPING` и настройки `TUIST_PREFIX_MAPPING_FOR_COVERAGE_*`. Эти настройки входят в состав хэшей кэша модулей, поэтому в Xcode 27 и новее включение или отключение `enableCaching` изменяет хэши ваших целей.

### Повторное использование частей больших выходных данных {#reusing-parts-of-large-outputs}

Кэш Xcode может сократить объём передаваемых данных благодаря фрагментации, определяемой содержимым. Вместо того чтобы считать каждый большой выходной файл не связанным с предыдущими версиями, он разбивает сжатый выходной файл на границы, определяемые его содержимым. После редактирования совпадающие фрагменты могут быть повторно использованы, даже если их смещения изменились.

При выгрузке отправляются только те фрагменты, которых нет на сервере. При скачивании сначала получается точное кэшированное действие и рецепт фрагментов выходного файла, затем повторно используются проверенные фрагменты, хранящиеся на локальной машине, и загружаются недостающие части. Полный восстановленный выходной файл проверяется перед восстановлением в кэше компилятора.

Кэш фрагментов передачи отделён от `DerivedData`, поэтому его фрагменты могут сохраниться при очистке кэша компиляции или перезапуске локального сервиса кэша. Он является временным и ограничен максимум одним гибибайтом полезной нагрузки фрагментов, с дополнительным временным промежуточным файлом размером не более двух мебибайт. Вытесненные или повреждённые фрагменты загружаются заново при необходимости. Сохранение самого кэша компиляции всё ещё быстрее, чем восстановление его содержимого.

Клиент использует передачу по фрагментам только тогда, когда сервер сообщает о совместимой поддержке. Старые клиенты всё ещё могут читать полные выходные данные, а клиенты, подключённые к старым или неподдерживаемым серверам, продолжают использовать обычную передачу. Небольшие выходные данные остаются на существующем пути передачи целого файла.

Это уменьшает объём переданных байтов, но не влияет на инвалидацию компилятора. Изменение исходного файла всё ещё может требовать компиляции; фрагментация помогает опубликовать или восстановить полученный результат. Экономия зависит от выходных данных и внесённых правок, а «холодная» машина без совпадающих фрагментов должна загрузить весь результат.

### Непрерывная интеграция {#continuous-integration}

Чтобы включить кэширование в вашей среде CI, нужно выполнить ту же команду, что и в локальных средах: `tuist setup cache`.

Для аутентификации можно использовать либо <.localized_link href="/guides/server/authentication#oidc-tokens">аутентификацию OIDC</.localized_link> (рекомендуется для поддерживаемых CI-провайдеров), либо <.localized_link href="/guides/server/authentication#account-tokens">токен учётной записи</.localized_link> через переменную окружения `TUIST_TOKEN`.

Пример рабочего процесса для GitHub Actions с использованием аутентификации OIDC:
```yaml
name: Build

permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: jdx/mise-action@v2
      - run: tuist auth login
      - run: tuist setup cache
      - # Your build steps
```

Смотрите <.localized_link href="/guides/integrations/continuous-integration">руководство по непрерывной интеграции</.localized_link> для получения дополнительных примеров, включая аутентификацию на основе токенов и другие CI-платформы, такие как Xcode Cloud, CircleCI, Bitrise и Codemagic.

### Хранилище кэша компиляции в CI {#compilation-cache-store-on-ci}

Хранилище кэша компиляции — это локальный каталог, где Xcode хранит результаты компиляции. Настройка сборки `COMPILATION_CACHE_CAS_PATH` определяет его расположение, которое по умолчанию равно `CompilationCache.noindex` внутри `DerivedData`.

#### Сохраняемое хранилище {#stateful-store}

Чтобы сохранять хранилище между сборками, направьте `COMPILATION_CACHE_CAS_PATH` (и `TUIST_COMPILATION_CACHE_CAS_PATH` для `tuist cache`) на один надёжный путь и ограничьте его размер с помощью [лимита размера хранилища](#store-size-limit).

## Устранение неполадок {#troubleshooting}

### Сборки предупреждают о сбое прокси-сервера кэша Xcode {#cas-proxy-failed}

Если сборка показывает предупреждение, подобное следующему, которое Xcode предваряет `CAS error:` или `CAS operation failed:` в зависимости от того, какая компиляция первой столкнулась с ошибкой:

```
warning: CAS error: The Tuist Xcode cache proxy at /Users/you/.local/state/tuist/cas-proxy.sock failed (proxy connect: No such file or directory (os error 2)). Compilations that needed it used the local cache only, without remote cache hits. Their uploads are kept on disk and sent once the proxy is reachable again. Run `tuist setup cache` if the proxy is not running.
```

значит, кэш компиляции не смог связаться с локальным прокси-сервером кэша, который устанавливает `tuist setup cache`. Сборка всё равно завершается успешно, но затронутые компиляции не получают попаданий в удалённый кэш, поэтому она выполняется так, будто кэш пуст. Их выгрузки сохраняются на диске и отправляются, как только прокси снова начнёт обрабатывать запросы: позже в той же сборке, если он восстановится вовремя, иначе — во время следующей сборки на той же машине. Машина CI, которая удаляется после завершения задачи, теряет их. Предупреждение появляется один раз за сборку в навигаторе проблем Xcode и в выводе `xcodebuild`.

Чтобы проверить, работает ли прокси, найдите процесс, слушающий сокет, указанный в предупреждении:

```bash
lsof ~/.local/state/tuist/cas-proxy.sock
```

Если команда ничего не выводит, запустите `tuist setup cache`, чтобы снова запустить прокси. В CI запускайте `tuist setup cache` перед любым вызовом `xcodebuild` в каждой задаче.

### Сборки работают крайне медленно и выдают предупреждения `CAS error: deadlineExceeded`{#cas-deadline-exceeded}

Если ваши сборки занимают гораздо больше времени, чем ожидалось, а журнал сборки Xcode заполнен предупреждениями вроде:

```
Warning: CAS error: deadlineExceeded(connectionError: Optional(connect(descriptor:addr:size:): No such file or directory (errno: 2)))
note: cache key query failed
```

или:

```
Warning: CAS error: deadlineExceeded(connectionError: Optional(connect(descriptor:addr:size:): Connection refused (errno: 61)))
```

значит, `COMPILATION_CACHE_REMOTE_SERVICE_PATH` указывает на сокет, который никто не слушает, обычно это сокет для каждого проекта (`~/.local/state/tuist/<org>_<project>.sock`), который настраивали более ранние версии Tuist. Tuist больше не обслуживает этот сокет. Xcode повторяет попытку подключения при каждом запросе к кэшу компиляции вместо быстрого отказа, из-за чего сборка может занимать час и более, и Tuist не может изменить это поведение.

Чтобы исправить это:

- **Сгенерированные проекты**: снова выполните `tuist generate`.
- **Другие проекты**: замените настройки сборки `COMPILATION_CACHE_*` на те, которые выводит `tuist setup cache`, как описано в разделе [Настройка параметров сборки Xcode](#configure-xcode-build-settings).

Если вы не используете кэш Xcode, вместо этого удалите настройки сборки `COMPILATION_CACHE_*` и выполните `tuist teardown cache`.

### `uploaded CAS output` появляется локально, даже если выгрузка отключена {#uploaded-cas-output-with-upload-disabled}

Когда установлено `xcodeCache: .xcodeCache(upload: false)` (или `upload: Environment.isCI` на машине, не являющейся CI), вы всё ещё можете видеть `note: uploaded CAS output ...` в журнале сборки. У `xcodebuild` нет возможности пропустить эти вызовы, поэтому Tuist всё ещё получает их, но ничего не публикует на сервере Tuist. Метрики панели управления учитывают это, поэтому ложный трафик выгрузки не отображается.
