# Кэш модулей {#module-cache}

> [!WARNING]
> **Требования**
>
> - <.localized_link href="/guides/features/projects">Сгенерированный проект</.localized_link>. Кэш модулей считывает граф проекта, который Tuist хранит за `Project.swift`, чтобы хешировать цели и заменять их бинарными файлами.

Кэш модулей Tuist предоставляет мощный способ оптимизации времени сборки, кэшируя ваши модули в виде бинарных файлов (`.xcframework`s) и предоставляя доступ к ним из разных окружений. Эта возможность позволяет использовать ранее сгенерированные бинарные файлы, сокращая необходимость повторной компиляции и ускоряя процесс разработки.

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

## Подготовка кэша {#warming}

Tuist эффективно <.localized_link href="/guides/features/projects/hashing">использует хеши</.localized_link> для каждой цели в графе зависимостей, чтобы обнаруживать изменения. Используя эти данные, он собирает бинарные файлы на основе этих целей и присваивает им уникальные идентификаторы. На этапе генерации графа Tuist прозрачно подменяет исходные цели их соответствующими бинарными версиями.

Эта операция, известная как *«подготовка»*, создает бинарные файлы для локального использования или для обмена с коллегами и CI-окружениями через Tuist. Процесс подготовки кэша прост и может быть запущен одной командой:

```bash
tuist cache
```

Команда повторно использует бинарные файлы, чтобы ускорить процесс.

Если загрузка одного бинарного файла не удается, команда всё равно загружает остальные, затем завершается с ненулевым статусом и перечисляет цели, которые не были загружены. Бинарные файлы в локальном кэше машины считаются закэшированными, поэтому чтобы загрузить их снова с той же машины, выполните `tuist clean binaries` перед подготовкой. Передайте `--no-upload`, чтобы сохранять бинарные файлы только в локальном кэше.

### Выбор назначения {#destination-selection}

Используйте `--destination simulator` или `--destination device`, чтобы кэшировать, генерировать и тестировать для одного назначения:

```bash
tuist cache --destination simulator
tuist generate --destination simulator
tuist test --destination simulator

tuist cache --destination device
tuist generate --destination device
tuist test --destination device -- -destination 'platform=iOS,id=DEVICE_IDENTIFIER'
```

По умолчанию используется `all`, что сохраняет все назначения, поддерживаемые вашими целями, включая Mac Catalyst. Последующий вызов `tuist cache` повторно использует закэшированные срезы и собирает только недостающие SDK. Обычная генерация сохраняет исходники модуля, если отсутствуют какие-либо требуемые срезы.

Ограниченная генерация ограничивает исходные цели выбранным назначением и сохраняет нативные цели macOS, включая макросы. Ни один из ограниченных режимов не включает Mac Catalyst. Выполните повторную генерацию с `--destination all`, чтобы восстановить все назначения.

`tuist test --destination` использует и загружает только срезы выбранного назначения, поэтому прогон тестов на симуляторе может использовать бинарные файлы из подготовки только для симулятора или полной подготовки. Он завершается ошибкой, если назначение, переданное в `xcodebuild` после `--`, не совпадает, а `--destination device` требует указания устройства через `-destination`. Хеши выборочного тестирования не зависят от назначения, поэтому прогоны с разными значениями `--destination` используют общие результаты тестов.

Посрезовое кэширование поддерживает iOS и macOS со стандартными архитектурами. Другие платформы, пользовательские архитектуры и неподдерживаемые продукты сохраняют полноразмерное кэширование артефактов. Устаревшее кэширование модулей всегда загружает полные артефакты и требует `--destination all` при подготовке.

### Допуск удаленной загрузки {#remote-upload-admission}

Современное кэширование модулей использует REAPI. Когда перегруженный кэш временно отклоняет загрузку с ошибкой `RESOURCE_EXHAUSTED`, Tuist выполняет откат с джиттером, соблюдает стандартные минимальные задержки `google.rpc.RetryInfo` и повторяет попытки в рамках ограниченного бюджета ожидания. Допуск загрузки разрешает не более шести повторных попыток на вызов. Каждая операция загрузки блоба делит один 60-секундный совокупный бюджет отката между проверками наличия, пакетными загрузками и потоковыми записями; одновременные ожидания расходуют этот бюджет, поэтому многократные отказы не дают каждому поставленному в очередь блобу еще одну минуту на повторные попытки. Успешные передачи не расходуют этот бюджет и не отменяются при его исчерпании. Публикация результатов действий имеет собственный ограниченный бюджет. Экспоненциальная задержка начинается с одной секунды и растет до 30 секунд перед применением пропорционального джиттера. Если требуемая сервером задержка превышает оставшийся бюджет, Tuist завершает работу с ошибкой, вместо того чтобы повторять попытку раньше указанного срока. Отмена прерывает откат, а чтения кэша сохраняют короткие повторные попытки, чтобы перегрузка не блокировала генерацию.

Эти настройки по умолчанию также помогают старым версиям Kura без подсказок о повторных попытках. Более длительные повторные попытки поглощают временную конкуренцию, а не постоянную перегрузку: уменьшите [лимит параллелизма кэша](#cache-concurrency-limit) для задач подготовки или увеличьте мощность сервера, если отказы продолжаются. См. [размеры загрузки Kura](https://github.com/tuist/tuist/blob/main/kura/README.md#upload-admission-and-sizing) для оценок памяти пода и метрик допуска.

### Выбор конфигурации {#configuration-selection}

При подготовке кэша без передачи `--configuration` Tuist выбирает конфигурацию сборки в следующем порядке:

1. [`defaultConfiguration`](https://projectdescription.tuist.dev/documentation/projectdescription/tuist/generationoptions/defaultconfiguration), заданный в `Project.Options.generationOptions` вашего манифеста, если таковой имеется.
2. В противном случае — первая конфигурация сборки варианта `debug`, отсортированная по имени в алфавитном порядке.

Чтобы подготовить кэш для конкретной конфигурации, передайте её явно:

```bash
tuist cache --configuration Release
```

## Использование {#usage}

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

::: code-group
```bash [Project generation]
tuist generate # Only dependencies
tuist generate Search # Dependencies + Search dependencies
tuist generate Search Settings # Dependencies, and Search and Settings dependencies
tuist generate --cache-profile none # No cache at all
```

```bash [Testing]
tuist test
```
<!-- -->
:::

> [!WARNING]
> Бинарное кэширование — это функция, предназначенная для рабочих процессов разработки, таких как запуск приложения на симуляторе или устройстве, или выполнение тестов. Она не предназначена для релизных сборок. При архивации приложения сгенерируйте проект с исходниками, используя `--cache-profile none`.

## Профили кэша {#cache-profiles}

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

- Встроенные:
  - `only-external`: заменять только внешние зависимости (системное значение по умолчанию)
  - `all-possible`: заменять как можно больше целей (включая внутренние цели)
  - `none`: никогда не заменять закэшированными бинарными файлами

Выберите профиль с помощью `--cache-profile` в `tuist generate`:

```bash
# Built-in profiles
tuist generate --cache-profile all-possible

# Custom profiles (defined in Tuist Config)
tuist generate --cache-profile development

# Use config default (no flag)
tuist generate

# Focus on specific targets (implies all-possible)
tuist generate MyModule AnotherTarget

# Disable binary replacement entirely
tuist generate --cache-profile none
```

> [!NOTE]
> **Устаревший флаг**
>
> Флаг `--no-binary-cache` устарел. Вместо него используйте `--cache-profile none`. Устаревший флаг по-прежнему работает для обеспечения обратной совместимости.

Приоритет при определении эффективного поведения (от высшего к низшему):

1. `--cache-profile none`
2. Фокус на цели (передача целей в `generate`) → профиль `all-possible`
3. `--cache-profile <value>`
4. Значение по умолчанию из конфигурации (если задано)
5. Системное значение по умолчанию (`only-external`)

## Поддерживаемые продукты {#supported-products}

Tuist может кэшировать только следующие типы целей:

- Фреймворки (статические и динамические), включая фреймворки поддержки тестов, которые зависят от [XCTest](https://developer.apple.com/documentation/xctest) или Swift Testing
- Библиотеки (статические и динамические), включая библиотеки поддержки тестов, которые зависят от XCTest или Swift Testing
- Бандлы
- Макросы Swift

Тестовые бандлы остаются исключёнными из модульного кэша. Это означает, что цели `unitTests` и `uiTests` не кэшируются как бинарные файлы, но обычные цели фреймворков и библиотек, от которых зависят тесты, могут быть закэшированы, даже если они линкуются с XCTest или Swift Testing.

Кэшированные библиотеки в формате `.xcframework` сохраняют метаданные, необходимые сгенерированным проектам для их импорта, включая модули Swift и публичные заголовки C/Objective-C, когда исходная цель объявляет публичные заголовки.

> [!NOTE]
> **Зависимости верхнего уровня**
>
> Если цель не подлежит кэшированию, это делает некешируемыми и цели верхнего уровня. Например, если у вас есть граф зависимостей `A > B`, где A зависит от B, и B не подлежит кэшированию, то A также не будет подлежать кэшированию.

## Аналитика {#analytics}

Откройте раздел **Module Cache → Modules** в панели управления вашего проекта, чтобы найти модули с частыми промахами. Выберите среду, которую хотите улучшить, например **CI**, и диапазон дат. В обзоре отображаются попадания в кэш, промахи и модули с промахами; при открытии модуля показывается его история и причина, назначенная каждому наблюдению.

В раскрывающемся списке **Misses** выбирается количество и объяснение для одной причины. Диаграмма показывает распределение всех четырёх причин. На странице модуля используйте фильтр **Reason** в истории, чтобы изучить отдельные случаи. Наведите курсор на значок причины или выберите его с клавиатуры, чтобы увидеть определение.

### Причины промахов {#miss-reasons}

| Причина | Что это значит |
| --- | --- |
| **Изменено** | Изменились собственные сравниваемые входные данные модуля. К ним относятся хеши файлов, настройки сборки, разрешённая конфигурация и идентификатор компилятора. Изменение исходного кода — лишь одна из возможных причин. |
| **Верхний уровень** | Собственные сравниваемые входные данные модуля остались прежними, но изменился хеш зависимости или внешнего пакета. Исходные файлы модуля могли остаться без изменений. |
| **Холодный старт** | Нет предыдущего наблюдения за модулем для сравнения, либо сообщённые входные данные не объясняют промах, и нет достаточных доказательств предыдущей доступности на удалённом сервере. Холодный старт не доказывает, что модуль никогда не кэшировался. |
| **Вытеснено** | Точный ключ кэша ранее имел попадание на удалённом сервере в том же проекте и на той же записанной конечной точке кэша, но теперь происходит промах. |

Для промахов с меткой **Вытеснено** артефакт был ранее загружен из удалённого кэша, но не мог быть повторно использован в этот раз. Наиболее вероятная причина — вытеснение, хотя промах также может объясняться ошибками доступа или загрузки. Tuist присваивает эту метку только тогда, когда находит предыдущее удалённое попадание; предыдущих промахов и локальных попаданий недостаточно.

Например:

| Сценарий | Классификация |
| --- | --- |
| Модуль даёт промах без предыдущего наблюдения или квалифицирующего удалённого попадания | Холодный старт |
| A изменяется; B зависит от A, а C зависит от B; все три ключа изменяются | A — Изменено; B и C — Верхний уровень |
| Версия компилятора изменяется после подготовки кэша, при этом исходники и настройки остаются неизменными | Затронутые промахи классифицируются как Изменено, если оба наблюдения сообщают входные данные компилятора |
| Точный ключ был загружен удалённо, затем произошёл промах после вытеснения его артефакта | Вытеснено, если предыдущее попадание является достаточным доказательством |
| Ключ постоянно даёт промахи и никогда не был успешно подготовлен к кэшированию | Может оставаться Холодным стартом |

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

### Улучшение процента попаданий в кэш {#improving-cache-hit-rate}

1. **Выберите согласованную базовую линию.** Начните с CI и репрезентативного диапазона дат. Отсортируйте модули по количеству промахов, затем учтите их процент попаданий, зависимые модули и стоимость сборки. Исправление часто пропускаемой дорогостоящей зависимости может сэкономить больше времени, чем улучшение процента попаданий для крошечного модуля. Сравнивайте одну и ту же среду и схожие нагрузки после внесения изменений.
2. **Исследуйте промахи типа Изменено.** Откройте соответствующие запуски и сравните их полные ключи и сообщённые входные данные. Согласуйте задачи подготовки кэша и его использования по целевой версии Xcode/компилятора, конфигурации и назначениям целей. Повторно подготовьте кэш после преднамеренных изменений. Если нестабильные сгенерированные файлы или зависящие от среды настройки делают недействительными иначе стабильные модули, исследуйте эти входные данные. Сохраняйте в хеше входные данные, влияющие на бинарную совместимость.
3. **Отслеживайте промахи типа Верхний уровень до изменённой зависимости.** Изучите её историю, чтобы найти прямое изменение. Подготовка кэширования результирующих ключей может восстановить повторное использование. Если часто изменяемая реализация делает недействительными множество дорогостоящих зависимых модулей, рассмотрите возможность разделения на более мелкие модули или использования стабильных интерфейсов, как описано в разделе [Эффективность](#efficiency).
4. **Проверьте охват подготовки кэша для промахов типа Холодный старт.** Убедитесь, что подготовка выбирает необходимые модули, использует конфигурацию и среду задачи-потребителя и успешно загружает артефакты. Проверьте полные ключи, используемые фактическими задачами CI. Если подготовка и потребление запрашивают разные ключи, проверьте входные данные хеширования, прежде чем предполагать, что кэш был вытеснен. Повторяющиеся промахи без предыдущей успешной загрузки возможны даже если исходники модуля не изменились.
5. **Используйте доказательства для промахов типа Вытеснено.** Подтвердите ключ и конечную точку запуска-потребителя, затем изучите предупреждения кэша этого запуска и результат загрузки задачи подготовки. При необходимости проверьте политики хранения или вытеснения. Повторно подготовьте необходимые артефакты и проверьте последующее попадание. Если промахи продолжаются, предоставите ссылки на соответствующие запуски и логи в службу поддержки.

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

```bash
tuist hash cache --configuration Debug --verbose
```

Сравните полный хеш модуля и блок компонентов. Повторение команды на той же неизменённой машине обычно должно давать тот же результат; сравните фактические среды подготовки и потребления, чтобы исследовать несоответствие. Ни одной из команд не требуется попадание в кэш. См. <.localized_link href="/guides/features/projects/hashing#debugging">диагностику хеширования</.localized_link> для дальнейших проверок.

## Эффективность {#efficiency}

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

1. Избегайте сильно вложенных графов зависимостей. Чем менее глубок граф, тем лучше.
2. Определяйте зависимости через цели протоколов/интерфейсов вместо целей реализации и внедряйте реализации через инъекцию зависимостей из самых верхних целей.
3. Разделяйте часто изменяемые цели на более мелкие, вероятность изменения которых ниже.

Вышеуказанные рекомендации являются частью <.localized_link href="/guides/features/projects/tma-architecture">Модульной архитектуры</.localized_link>, которую мы предлагаем как способ структурирования ваших проектов для максимизации преимуществ не только бинарного кэширования, но и возможностей Xcode.

## Рекомендуемая настройка {#recommended-setup}

Мы рекомендуем иметь задачу CI, которая **запускается при каждом коммите в основной ветке** для подготовки кэша. Это обеспечит наличие в кэше бинарных файлов для изменений в `main`, чтобы локальные сборки и сборки веток в CI выполнялись инкрементально на их основе.

> [!TIP]
> **Держите подготовку кэша изолированной**
>
> Запускайте `tuist cache` в отдельном шаге CI без последующих шагов, зависящих от сгенерированного рабочего пространства. Поскольку `tuist cache` изменяет рабочее пространство для целей сборки кэша, любые шаги CI, которым нужно рабочее пространство, должны сначала запустить `tuist generate`, чтобы получить свежее, пригодное для использования рабочее пространство.

> [!TIP]
> **Подготовка кэша использует бинарные файлы**
>
> Команда `tuist cache` также использует бинарный кэш для ускорения подготовки.

Ниже приведены примеры распространённых рабочих процессов:

### Разработчик начинает работу над новой функцией {#a-developer-starts-to-work-on-a-new-feature}

1. Он создаёт новую ветку от `main`.
2. Он запускает `tuist generate`.
3. Tuist загружает самые свежие бинарные файлы из `main` и генерирует проект с их использованием.

### Разработчик отправляет изменения вверх по потоку {#a-developer-pushes-changes-upstream}

1. Конвейер CI запустит `xcodebuild build` или `tuist test` для сборки или тестирования проекта.
2. Рабочий процесс загрузит самые свежие бинарные файлы из `main` и сгенерирует проект с их использованием.
3. Затем он выполнит сборку или тестирование проекта инкрементально.

## Конфигурация {#configuration}

### Лимит параллелизма кэша {#cache-concurrency-limit}

Установите `TUIST_CACHE_CONCURRENCY_LIMIT` в положительное целое число, чтобы ограничить как загрузки, так и выгрузки. Например, уменьшите нагрузку на небольшой самостоятельно размещённый кэш в задачах подготовки:

```bash
TUIST_CACHE_CONCURRENCY_LIMIT=2 tuist cache
```

Если значение не установлено, выгрузки REAPI используют восемь задач передачи. Загрузки используют восемь, когда любой блоб требует ByteStream, и 32 для планов только с пакетной обработкой. Устаревший путь HTTP-кэша по умолчанию равен 100; этот параметр по умолчанию не применяется к REAPI. Неверные значения, включая ранее документированный `none`, сохраняют значения по умолчанию, а не удаляют ограничения. Используйте `unset TUIST_CACHE_CONCURRENCY_LIMIT`, чтобы восстановить значения по умолчанию.

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

### Временная директория для подготовки кэша {#cache-warm-scratch-directory}

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

Путь может быть абсолютным или относительным текущей рабочей директории. Tuist создаёт директорию, если она не существует. Если она уже существует, это должна быть пустая директория.

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

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

### Покрытие кода {#code-coverage}

> [!NOTE] EARLY ACCESS
> Покрытие кода с модульным кэшем находится в раннем доступе. Команды читают и подготавливают инструментированные бинарные файлы, описанные ниже, только когда установлен `TUIST_FEATURE_FLAG_COVERAGE=1`.

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

```swift
import ProjectDescription

let tuist = Tuist(
    project: .tuist(
        generationOptions: .options(
            coverage: .coverage(enabled: true)
        )
    )
)
```

С `enabled` каждая команда и каждое окружение читает одну инструментированную версию кэша для целей вашего проекта, поэтому одна подготовка на CI обслуживает и CI, и локальные машины:

| Команда | Цели вашего проекта | Внешние пакеты |
| --- | --- | --- |
| `tuist cache` (конфигурация Debug) | Подготавливает инструментированные бинарные файлы | Подготавливает обычные бинарные файлы |
| `tuist cache` (конфигурация Release) | Подготавливает обычные бинарные файлы | Подготавливает обычные бинарные файлы |
| `tuist hash cache` | Выводит инструментированные ключи | Выводит обычные ключи |
| `tuist generate` | Читает инструментированные бинарные файлы | Читает обычные бинарные файлы |
| `tuist test` | Читает инструментированные бинарные файлы | Читает обычные бинарные файлы |

Опция применяется ко всем конфигурациям, которые Xcode считает Debug. Сборки Release никогда не инструментруются. Tuist также линкует runtime профилирования в этих конфигурациях (`CLANG_COVERAGE_MAPPING_LINKER_ARGS`), поэтому сборки, которые не собирают покрытие, всё равно линкуют инструментированные бинарные файлы, и включает покрытие в действии тестирования схем, которые он генерирует автоматически, и схем, которые вы определяете и оставляете `coverage` неустановленным.

Схема, которую вы определяете, следует опции, если сама не устанавливает покрытие: `.options(coverage: false)` держит его выключенным, а `.options(coverage: true)` держит включённым независимо от того, что говорит опция. Планы тестов сами решают вопрос покрытия, а `-enableCodeCoverage` всё ещё переопределяет запуск, как в Xcode. Запуск, который читает инструментированные бинарные файлы без сбора покрытия, выполняет сборку и тестирование нормально. Когда запуск собирает покрытие, но цели вашего проекта пришли из кэша как обычные бинарные файлы, Tuist предупреждает, что их покрытие не измеряется.

Переменная окружения `TUIST_COVERAGE_ENABLED` (`1` или `0`) имеет приоритет над `coverage: .coverage(enabled:)`. Установите её для всего окружения, например для рабочего процесса CI, а не для одной команды, чтобы команды, подготавливающие кэш, и команды, читающие его, согласовывались.

`prefixMapping` (см. <.localized_link href="/guides/features/cache/xcode-cache#coverage-with-prefix-mapping">кэш Xcode</.localized_link>) имеет собственное переопределение: переменная окружения `TUIST_COVERAGE_PREFIX_MAPPING` (`1` или `0`) имеет приоритет над `coverage: .coverage(prefixMapping:)`.

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

> [!IMPORTANT] KEEP THE VALUES THE SAME EVERYWHERE
> `enabled` и `prefixMapping` изменяют настройки сборки и ключи кэша целей вашего проекта, а также хэши выборочного тестирования его тестовых целей. Установите их в одинаковое значение на каждой машине, которая использует общий кэш, и не выводите их из окружения (например, из `Environment.isCI`): значение, отличающееся между CI и локальными машинами, даст им разные ключи. То же самое относится к переменным окружения: запуск с `TUIST_COVERAGE_ENABLED=0` не переиспользует бинарные файлы или результаты выборочного тестирования запусков с включённым покрытием.

Имейте в виду:

- Инструментированные бинарные файлы больше: примерно на 20–30% для статических архивов и динамических библиотек. Сборки Debug работают с той же скоростью.
- Отчёт о покрытии Xcode никогда не показывает код, взятый из кэша, независимо от этой опции. Загрузка покрытия Tuist измеряет его. Чтобы увидеть покрытие цели в Xcode, сфокусируйтесь на ней с помощью `tuist generate <target>`, чтобы она собиралась из исходного кода.

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

### Не используются бинарные файлы для моих целей {#it-doesnt-use-binaries-for-my-targets}

Убедитесь, что <.localized_link href="/guides/features/projects/hashing#debugging">хэши детерминированы</.localized_link> в разных окружениях и запусках. Это может произойти, если проект ссылается на окружение, например через абсолютные пути. Вы можете использовать команду `diff` для сравнения проектов, сгенерированных двумя последовательными вызовами `tuist generate` или в разных окружениях или запусках.

Также убедитесь, что цель не зависит напрямую или косвенно от <.localized_link href="/guides/features/cache/module-cache#supported-products">некешируемой цели</.localized_link>.

### Отсутствующие символы {#missing-symbols}

При использовании исходного кода система сборки Xcode через Derived Data может разрешать зависимости, которые не объявлены явно. Однако, когда вы полагаетесь на бинарный кэш, зависимости должны быть объявлены явно; иначе вы, скорее всего, увидите ошибки компиляции, когда символы не будут найдены. Для отладки мы рекомендуем использовать команду <.localized_link href="/guides/features/projects/inspect/implicit-dependencies">`tuist inspect dependencies --only implicit`</.localized_link> и настроить её в CI, чтобы предотвратить регрессии в неявной линковке.
