Менеджер пакетов Swift, конфигурации сборки и некомпилируемые проекты iOS

Swift Package Manager в Xcode — это новейший способ управления сторонними зависимостями Swift-проектов. Он очень аккуратно интегрирован и позволяет легко и чисто управлять зависимостями. По крайней мере, иногда.

TL;DR

В этой статье я рассказываю о борьбе с добавлением SPM в старый проект, содержащий фреймворки, не совместимые с симуляторами Apple Silicon iOS (arm64). Если вы спешите найти решение, переходите сразу к параграфу о конфигурациях сборки SPM.

При работе над greenfield-проектами SPM в большинстве случаев действительно легко использовать. Однако в реальности мы довольно часто сталкиваемся с работой над какими-то старыми проектами со всеми их причудами.

[Отказ от ответственности]: Описанные проблемы и их решения были протестированы на Xcode 13.2.1 и 13.4.1. Поведение может измениться в будущих релизах Xcode. Здесь вы можете найти репозиторий с примером проекта.

Проблема

На днях я пытался добавить Swift Package Manager в один из проектов, над которым я работаю, поскольку моя команда склонна переходить на SPM с других менеджеров зависимостей.

К моему удивлению, меня встретила большая жирная красная ошибка, препятствующая компиляции проекта:

Could not find module <package name> for target 'x86_64-apple-ios-simulator';
found: arm64, arm64-apple-ios-simulator

Войдите в полноэкранный режим Выйти из полноэкранного режима

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

Корень всех зол

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

Сама проблема исходит не от других менеджеров зависимостей, а скорее от настроек сборки проекта. Возможно, вы знакомы с обходным решением для запуска проектов с устаревшими фреймворками (например, «жирный» .framework, не созданный для симулятора iOS arm64) на кремниевых машинах Apple.

Есть два основных варианта решения этой проблемы:

  • Запустить Xcode с помощью Rosetta — кажется хорошей идеей и действительно работает, но за это приходится платить. Время чистой сборки для нашего проекта увеличилось со 112 до 165 секунд. Это почти на 50% дольше, и я подозреваю другие потери производительности во время повседневной работы.

  • Исключите архитектуру arm64 для iOS simulator sdk из конфигурации сборки для разработки. Это довольно простое и умное решение проблемы. Исключение архитектуры arm64 для симулятора заставляет xcode собирать наше приложение для архитектуры x86_64 на симуляторе iOS, который совместим с нашим устаревшим фреймворком (сообщение stackoverflow).

Несмотря на то, что мы явно исключаем архитектуру arm64 для симулятора iOS, мы получаем ошибку, показанную выше. Более того, в ней явно говорится, что SPM создал нашу зависимость только для архитектуры arm64. Мы можем сделать вывод, что SPM игнорирует настройки сборки нашего проекта.

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

Конфигурации сборки SPM

Если мы изучим документацию, то увидим, что существует debug и release BuildConfiguration. Мы также можем заглянуть в исходный код, но там не так много полезной информации. Так что же означает конфигурация debug и release и при каких обстоятельствах они применяются?

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

Debug build configuration применяется к зависимостям Swift Package Manager, если наша текущая конфигурация сборки содержит «debug» или «development» в своем имени (без учета регистра). Поэтому если вы пытаетесь собрать приложение в стандартной конфигурации Release, переименуйте Debug во что-то другое или создайте новую конфигурацию (например, Stage), и оно будет работать™. Это означает, что существует некая логика разбора имени конфигурации сборки проекта, которая затем преобразуется в различные конфигурации сборки зависимостей SPM.

Я хочу подчеркнуть это еще раз: как бы глупо это ни звучало, переименование конфигурации сборки проекта — это ключ к успеху. Она не может содержать Debug или Development в своем имени, чтобы собрать зависимости SPM в режиме Release.

Обратная проблема

Мы только что пришли к выводу, что нам нужна релизная конфигурация зависимостей SPM для нашего проекта в сценарии, описанном выше. Но в прошлом я уже сталкивался с подобной проблемой, правда, с другой стороны. Поскольку мы пишем Unit Tests, мы также писали их для внутренних пакетов, которые мы использовали для разделения кода. Оказалось, что мы столкнулись с проблемами при попытке запустить наши юнит-тесты вместе с другими тестовыми целями в основной схеме проекта:

Module <package name> was not compiled for testing
Вход в полноэкранный режим Выход из полноэкранного режима

Как вы уже догадались, решение здесь полностью противоположно тому, что мы только что сделали. Для того чтобы эта ошибка исчезла, мы должны скомпилировать наш Swift-пакет с отладочной конфигурацией, а это значит, что нам нужно добавить «debug» к имени нашей конфигурации разработки. Если в это же время вы решаете предыдущую проблему, то это невозможно. Мы решили ее, создав отдельную схему только для запуска модульных тестов локальных пакетов.

Выводы

Swift Package Manager — отличный способ управления сторонними зависимостями в проектах iOS. С новыми выпусками Xcode он становится все более полезным и мощным. К сожалению, SPM все еще является молодым дополнением к Xcode и ему не хватает некоторых функциональных возможностей. Кроме того, его эфемерный способ реализации приводит к проблемам, подобным тем, с которыми я столкнулся. В данном конкретном случае нам помогла бы явная документация, рассказывающая о логике разбора имен конфигурации сборки, применяемой к нашим Swift-пакетам. Если вы когда-нибудь окажетесь в подобной ситуации, надеюсь, эта статья поможет вам разобраться с ней 🙂

Оцените статью
devanswers.ru
Добавить комментарий