С визуализацией графа зависимостей были трудности: во-первых, из-за того, что объявление зависимостей у нас в проекте размазано по Podfile и yml-конфигам модулей для XcodeGen, а во-вторых, существующие решения с открытым кодом не всегда работают так, как хотелось бы (например, не поддерживают какой-то из менеджеров зависимостей; строят неинформативный граф; и тд)
Склоняюсь к тому, что для этой задачи потребуется реализовать собственную утилиту, как это например сделали в Badoo.
Может быть, у вас есть какие-то рекомендации на этот счет?
если я правильно понял, то появились проблемы с тем, как линкуются статические и динамические зависимости, и что нужно в XCodeGen-конфиге руками указывать какую встраивать в ваш модуль/фреймворк
Нет, с самим XcodeGen, к счастью, проблем вообще не возникло, там и поддержка xcframework быстро появилась (мы в итоге зависимости из Carthage перевели на xcframework-и для Xcode 12.5), и можно легко выбрать нужный способ интеграции зависимости:
dependencies:
# можно так
- carthage: Alamofire
# или так
- package: Alamofire
# или так
- framework: ${C_BUILD_PATH}/Alamofire.xcframework
# или вот так
- framework: ${C_BUILD_PATH}/Alamofire.xcframework
- linkType: dynamic # | static
1) при переезде на Xcode 12 Carthage не мог собрать ни одну зависимость, их сборки падали с ошибкой: "the same architectures (arm64) and can't be in the same fat output file". Исправилось все вот этим костылем, потому что мы не были готовы перевести зависимости в xcframework-и на тот момент.
2) при переезде на Xcode 12.3 перестали собираться тестовые таргеты на симулятор, вылезала ошибка:
Building for iOS Simulator but the linked library was built for Mac OS + iOS
Связано это было с тем, что зависимости собирались в universal framework-и, и для тестовых таргетов из них не убирались слайсы для лишних архитектур. Самостоятельно доработать в разумные сроки шаг удаления лишних архитектур не удалось, поэтому ждали обновления Carthage, чтобы поднять версию Xcode.
Также в большей части зависимостей был конфликт ключа VALID_ARCHS (deprecated с Xcode 12) и нового ключа EXCLUDED_ARCHS. Это была проблема самих зависимостей, но так вышло, что именно те, что были подключены через Carthage, еще долго не поддерживали Xcode 12 и нам приходилось использовать форки с исправлениями.
Какие-то проблемы с переездом были у CocoaPods, но решались быстрее. А делать и в будущем такую двойную работу больше не хотелось
Получается вы давно мечтали избавиться от гибкого инструмента?) (шутка)
Да, звучит слегка контринтуитивно) Но гибкость как раз и состоит в том, что часть работы по настройке Carthage мы выполняли сами. Какое-то время он не требовал особых доработок, но уже ближе к Xcode 12 регулярно начали возникать проблемы, решение которых требовало бОльших временных затрат. Вот и решили от него избавиться.
Вопрос №1: Может быть стоило написать свою систему управления линковкой?)
Не очень поняла вопрос: что подразумевается под системой управления линковкой и какие конкретно проблемы она должна решить?
Вопрос №2: SPM складывает все в DerivedData. ... Как живется с этим?)
Локальная сборка:
При холодной сборке шаг Resolve Swift Packages занимает в среднем около 70 сек. Чистить Derived Data нашим разработчикам требуется не часто, и пока что жалоб не было.
Сборка на CI:
Для команды xcodebuild можно указать путь, куда будут загружаться пакеты spm (это слепки репозиториев и артефакты):
-clonedSourcePackagesDirPath PATH specifies the directory to which remote source packages are fetch or expected to be found
Это и будет кэшом наших пакетов.
Если используется Fastlane, то эту настройку можно передать прямо команде gym или в Gymfile (cloned_source_packages_path "PATH"). Для CI мы используем связку Fastlane + Github Actions, работа с кэшом производится с помощью экшена actions/cache@v2, которому мы передаем путь, указанный в cloned_source_packages_path. Так что этот кэш не затирается при очистке DerivedData.
Действительно, большинство сторонних решений, которые поддерживают интеграцию через SwiftPM, следуют этой рекомендации и используют тип .automatic: он выбирается по умолчанию, если не указан явно тип .static или .dynamic.
Но (как минимум, начиная с Xcode 11.4) в таком случае выбиралась статическая линковка и этому даже посвящено несколько тредов на форумах Swift, вот например, один из них. Мы сами столкнулись с проблемой, что даже при линковке зависимости с несколькими нашими таргетами автоматически выбиралась статическая, что приводило к ошибке дублирования символов. И чтобы исправить эту ошибку приходилось заворачивать зависимость в модуль, который бы линковался динамически. Я даже находила описание такого решения на GitHub.
Вероятно, такое поведение могло быть исправлено в новых версиях Xcode, но на момент доклада мы использовали Xcode 12.5.1.
А в какой версии Xcode удалось получить такое поведение?
На практике SPM выберет динамику, если библиотека слинкована с несколькими таргетами
Нет, можно сделать свой приватный под, гайд вот тут. В этом случае спецификация будет храниться в нашем репо, и в Podfile будет указан к нему путь. Но приватные поды – это, скорее, инструмент для организации своих проектов: мы выносим свой код, для того, чтобы его можно было переиспользовать. В статье же я описывала работу со сторонними решениями.
звучит здорово)
С визуализацией графа зависимостей были трудности: во-первых, из-за того, что объявление зависимостей у нас в проекте размазано по Podfile и yml-конфигам модулей для XcodeGen, а во-вторых, существующие решения с открытым кодом не всегда работают так, как хотелось бы (например, не поддерживают какой-то из менеджеров зависимостей; строят неинформативный граф; и тд)
Склоняюсь к тому, что для этой задачи потребуется реализовать собственную утилиту, как это например сделали в Badoo.
Может быть, у вас есть какие-то рекомендации на этот счет?
Нет, с самим XcodeGen, к счастью, проблем вообще не возникло, там и поддержка xcframework быстро появилась (мы в итоге зависимости из Carthage перевели на xcframework-и для Xcode 12.5), и можно легко выбрать нужный способ интеграции зависимости:
Из того, что первым приходит на ум:
1) при переезде на Xcode 12 Carthage не мог собрать ни одну зависимость, их сборки падали с ошибкой: "the same architectures (arm64) and can't be in the same fat output file". Исправилось все вот этим костылем, потому что мы не были готовы перевести зависимости в xcframework-и на тот момент.
2) при переезде на Xcode 12.3 перестали собираться тестовые таргеты на симулятор, вылезала ошибка:
Связано это было с тем, что зависимости собирались в universal framework-и, и для тестовых таргетов из них не убирались слайсы для лишних архитектур. Самостоятельно доработать в разумные сроки шаг удаления лишних архитектур не удалось, поэтому ждали обновления Carthage, чтобы поднять версию Xcode.
Также в большей части зависимостей был конфликт ключа VALID_ARCHS (deprecated с Xcode 12) и нового ключа EXCLUDED_ARCHS. Это была проблема самих зависимостей, но так вышло, что именно те, что были подключены через Carthage, еще долго не поддерживали Xcode 12 и нам приходилось использовать форки с исправлениями.
Какие-то проблемы с переездом были у CocoaPods, но решались быстрее. А делать и в будущем такую двойную работу больше не хотелось
Да, звучит слегка контринтуитивно) Но гибкость как раз и состоит в том, что часть работы по настройке Carthage мы выполняли сами. Какое-то время он не требовал особых доработок, но уже ближе к Xcode 12 регулярно начали возникать проблемы, решение которых требовало бОльших временных затрат. Вот и решили от него избавиться.
Не очень поняла вопрос: что подразумевается под системой управления линковкой и какие конкретно проблемы она должна решить?
Локальная сборка:
При холодной сборке шаг
Resolve Swift Packages
занимает в среднем около 70 сек. Чистить Derived Data нашим разработчикам требуется не часто, и пока что жалоб не было.Сборка на CI:
Для команды
xcodebuild
можно указать путь, куда будут загружаться пакеты spm (это слепки репозиториев и артефакты):Это и будет кэшом наших пакетов.
Если используется Fastlane, то эту настройку можно передать прямо команде gym или в Gymfile (
cloned_source_packages_path "PATH"
). Для CI мы используем связку Fastlane + Github Actions, работа с кэшом производится с помощью экшена actions/cache@v2, которому мы передаем путь, указанный вcloned_source_packages_path
. Так что этот кэш не затирается при очистке DerivedData.Спасибо за замечание!
Действительно, большинство сторонних решений, которые поддерживают интеграцию через SwiftPM, следуют этой рекомендации и используют тип .automatic: он выбирается по умолчанию, если не указан явно тип .static или .dynamic.
Но (как минимум, начиная с Xcode 11.4) в таком случае выбиралась статическая линковка и этому даже посвящено несколько тредов на форумах Swift, вот например, один из них. Мы сами столкнулись с проблемой, что даже при линковке зависимости с несколькими нашими таргетами автоматически выбиралась статическая, что приводило к ошибке дублирования символов. И чтобы исправить эту ошибку приходилось заворачивать зависимость в модуль, который бы линковался динамически. Я даже находила описание такого решения на GitHub.
Вероятно, такое поведение могло быть исправлено в новых версиях Xcode, но на момент доклада мы использовали Xcode 12.5.1.
А в какой версии Xcode удалось получить такое поведение?
Нет, можно сделать свой приватный под, гайд вот тут. В этом случае спецификация будет храниться в нашем репо, и в Podfile будет указан к нему путь. Но приватные поды – это, скорее, инструмент для организации своих проектов: мы выносим свой код, для того, чтобы его можно было переиспользовать. В статье же я описывала работу со сторонними решениями.